Skip to content

Commit

Permalink
FINERACT-2169: New command processing infrastructure
Browse files Browse the repository at this point in the history
  • Loading branch information
vidakovic committed Jan 16, 2025
1 parent d704852 commit cdbd816
Show file tree
Hide file tree
Showing 34 changed files with 1,164 additions and 0 deletions.
2 changes: 2 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ buildscript {
[
'fineract-api',
'fineract-core',
'fineract-command',
'fineract-accounting',
'fineract-provider',
'fineract-branch',
Expand Down Expand Up @@ -112,6 +113,7 @@ plugins {
id "com.github.davidmc24.gradle.plugin.avro-base" version "1.9.1" apply false
id 'org.openapi.generator' version '7.8.0' apply false
id 'com.gradleup.shadow' version '8.3.5' apply false
id 'me.champeau.jmh' version '0.7.1' apply false
}

apply from: "${rootDir}/buildSrc/src/main/groovy/org.apache.fineract.release.gradle"
Expand Down
82 changes: 82 additions & 0 deletions fineract-command/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
description = 'Fineract Command'

apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'me.champeau.jmh'

configurations {
asciidoctorExtensions
providedRuntime // needed for Spring Boot executable WAR
providedCompile
compile() {
exclude module: 'hibernate-entitymanager'
exclude module: 'hibernate-validator'
exclude module: 'activation'
exclude module: 'bcmail-jdk14'
exclude module: 'bcprov-jdk14'
exclude module: 'bctsp-jdk14'
exclude module: 'c3p0'
exclude module: 'stax-api'
exclude module: 'jaxb-api'
exclude module: 'jaxb-impl'
exclude module: 'jboss-logging'
exclude module: 'itext-rtf'
exclude module: 'classworlds'
}
runtime
}

apply from: 'dependencies.gradle'

// Configuration for the modernizer plugin
// https://github.com/andygoossens/gradle-modernizer-plugin
modernizer {
ignoreClassNamePatterns = [
'.*AbstractPersistableCustom',
'.*EntityTables',
'.*domain.*'
]
}

// If we are running Gradle within Eclipse to enhance classes with OpenJPA,
// set the classes directory to point to Eclipse's default build directory
if (project.hasProperty('env') && project.getProperty('env') == 'eclipse') {
sourceSets.main.java.outputDir = new File(rootProject.projectDir, "fineract-command/bin/main")
}

if (!(project.hasProperty('env') && project.getProperty('env') == 'dev')) {
sourceSets {
test {
java {
exclude '**/core/boot/tests/**'
}
}
}
}

jmh {
// include = ['.*'] // Include all benchmarks (regex-based filter)
warmupIterations = 3 // Number of warm-up iterations
iterations = 5 // Number of measurement iterations
fork = 2 // Number of forks
timeOnIteration = '1s' // Time per iteration
benchmarkMode = ['thrpt'] // Default benchmark mode
}
60 changes: 60 additions & 0 deletions fineract-command/dependencies.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

dependencies {
implementation(
'org.springframework.boot:spring-boot-starter',
'org.springframework.boot:spring-boot-starter-validation',
'io.github.resilience4j:resilience4j-spring-boot3',

'com.google.guava:guava',

'org.apache.commons:commons-lang3',

'com.github.spotbugs:spotbugs-annotations',
'org.mapstruct:mapstruct',
'com.lmax:disruptor:3.4.4',
)
implementation('org.eclipse.persistence:org.eclipse.persistence.jpa') {
exclude group: 'org.eclipse.persistence', module: 'jakarta.persistence'
}

compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
annotationProcessor 'org.mapstruct:mapstruct-processor'
annotationProcessor 'org.openjdk.jmh:jmh-generator-annprocess:1.37'

asciidoctorExtensions 'org.springframework.restdocs:spring-restdocs-asciidoctor:3.0.3'

testImplementation ('org.springframework.boot:spring-boot-starter-test') {
exclude group: 'com.jayway.jsonpath', module: 'json-path'
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
exclude group: 'jakarta.activation'
exclude group: 'javax.activation'
exclude group: 'org.skyscreamer'
}
testImplementation (
'org.springframework.boot:spring-boot-starter-web',
'org.mockito:mockito-inline',
'org.openjdk.jmh:jmh-core:1.37',
'org.springframework.restdocs:spring-restdocs-mockmvc:3.0.3',
'org.springframework.restdocs:spring-restdocs-webtestclient:3.0.3',
'org.springframework.restdocs:spring-restdocs-restassured:3.0.3',
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.command.core;

import java.io.Serial;
import java.io.Serializable;
import java.time.Instant;
import java.util.UUID;
import lombok.Data;
import lombok.experimental.FieldNameConstants;

@Data
@FieldNameConstants
public abstract class Command<T> implements Serializable {

@Serial
private static final long serialVersionUID = 1L;

private UUID id;
private Instant createdAt;
private String tenantId;
private String username;
private T payload;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.command.core;

import lombok.experimental.UtilityClass;

@UtilityClass
public final class CommandConstants {

public static final String COMMAND_REQUEST_ID = "x-fineract-request-id";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.command.core;

import java.util.function.Supplier;

public interface CommandExecutor {

<REQ, RES> Supplier<RES> execute(Command<REQ> command);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.command.core;

import com.google.common.reflect.TypeToken;

public interface CommandHandler<REQ, RES> {

RES handle(Command<REQ> command);

default boolean matches(Command<REQ> command) {
TypeToken<REQ> handlerType = new TypeToken<>(getClass()) {};

return handlerType.getRawType().isAssignableFrom(command.getPayload().getClass());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.command.core;

@FunctionalInterface
public interface CommandMiddleware {

void invoke(Command<?> command);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.command.core;

import java.util.function.Supplier;

public interface CommandPipeline {

<REQ, RES> Supplier<RES> send(Command<REQ> command);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.command.core;

import java.io.Serial;
import java.io.Serializable;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.FieldNameConstants;
import org.springframework.boot.context.properties.ConfigurationProperties;

@Builder
@Data
@NoArgsConstructor
@AllArgsConstructor
@FieldNameConstants
@ConfigurationProperties(prefix = "fineract.command")
public final class CommandProperties implements Serializable {

@Serial
private static final long serialVersionUID = 1L;

@Builder.Default
private Boolean enabled = true;

@Builder.Default
private String executor = "sync";

@Builder.Default
private Integer ringBufferSize = 1024;
}
Loading

0 comments on commit cdbd816

Please sign in to comment.