Applying rejections in Aggregates in Spine Event Engine - domain-driven-design

I am trying to apply a rejection to the aggregate which threw it:
public class WalletAggregate extends Aggregate<WalletId, Wallet, Wallet.Builder> {
#Assign MoneyCharged handle(ChargeMoney cmd) throws InsuffisientFunds {
...
}
#Apply void on(MoneyCharged event) {
...
}
#Apply void on(InsuffisientFunds event) {
...
}
}
I can clearly see the MoneyChanged event applied. But when InsuffisientFunds is thrown, it is not applied. Am I missing something? How can I apply a thrown rejection to an aggregate?

Rejections don't work that way. A Rejection is more then just negative-case Event. It is emitted when an illegal operation is attempted and the handler (in your case, the Aggregate) refuses (rejects) to execute the Command, and thus does not change its state.
In practice, you might want to consider creating a separate entity that would process Rejections.
If you want to store the failed actions of a user, a Projection would probably work best:
public class ChargeAttemptsProjection extends Projection<...> {
#Subscribe
void on(InsuffisientFunds rejection) {
// Update the state of the Projection.
}
}
If there is a flow for recovering from the faulty situation, a ProcessManager sounds more fit.
public class FailedTransactionRecovery extends ProcessManager<...> {
#React
YourOtherEvent on(InsuffisientFunds rejection) {
// Start the recovery process.
}
}
Last but not least, there's always the possibility to subscribe to the Rejection on the client to handle it gracefully on the UI.
See the JS reference documentation for more on client-side subscriptions.

Related

How to connect two different ViewModels in Kotlin AndroidStudio

I have two different View Models with their own fragments, and I want my arrayListB in ViewModelB have the same value of my arrayListA in ViewModelA.
I am sure this may help you to do that!
Architecture Components provides ViewModel helper class for the UI controller that is responsible for preparing data for the UI. ViewModel objects are automatically retained during configuration changes so that data they hold is immediately available to the next activity or fragment instance. For example, if you need to display a list of users in your app, make sure to assign responsibility to acquire and keep the list of users to a ViewModel, instead of an activity or fragment, as illustrated by the following sample code:
class MyViewModel : ViewModel() {
private val users: MutableLiveData<List<User>> by lazy {
MutableLiveData<List<User>>().also {
loadUsers()
}
}
fun getUsers(): LiveData<List<User>> {
return users
}
private fun loadUsers() {
// Do an asynchronous operation to fetch users.
}
}
for more information see this :
(https://developer.android.com/topic/libraries/architecture/viewmodel?msclkid=bf393d12ce9011eca291710e2d69c5af)

the right way to return a Single from a CompletionStage

I'm playing around with reactive flows using RxJava2, Micronaut and Cassandra. I'm new to rxjava and not sure what is the correct way to return a of List Person in the best async manner?
data is coming from a Cassandra Dao interface
public interface PersonDAO {
#Query("SELECT * FROM cass_drop.person;")
CompletionStage<MappedAsyncPagingIterable<Person>> getAll();
}
that gets injected into a micronaut controller
return Single.just(personDAO.getAll().toCompletableFuture().get().currentPage())
.subscribeOn(Schedulers.io())
.map(people -> HttpResponse.ok(people));
OR
return Single.just(HttpResponse.ok())
.subscribeOn(Schedulers.io())
.map(it -> it.body(personDAO.getAll().toCompletableFuture().get().currentPage()));
OR switch to RxJava3
return Single.fromCompletionStage(personDAO.getAll())
.map(page -> HttpResponse.ok(page.currentPage()))
.onErrorReturn(throwable -> HttpResponse.ok(Collections.emptyList()));
Not a pro of RxJava nor Cassandra :
In your first and second example, you are blocking the thread executing the CompletionStage with get, even if you are doing it in the IO thread, I would not recommand doing so.
You are also using a Single wich can emit, only one value, or an error. Since you want to return a List, I would sugest to go for at least an Observable.
Third point, the result from Cassandra is paginated, I don't know if it's intentionnaly but you list only the first page, and miss the others.
I would try a solution like the one below, I kept using the IO thread (the operation may be costly in IO) and I iterate over the pages Cassandra fetch :
/* the main method of your controller */
#Get()
public Observable<Person> listPersons() {
return next(personDAO.getAll()).subscribeOn(Schedulers.io());
}
private Observable<Person> next(CompletionStage<MappedAsyncPagingIterable<Person>> pageStage) {
return Single.fromFuture(pageStage.toCompletableFuture())
.flatMapObservable(personsPage -> {
var o = Observable.fromIterable(personsPage.currentPage());
if (!personsPage.hasMorePages()) {
return o;
}
return o.concatWith(next(personsPage.fetchNextPage()));
});
}
If you ever plan to use reactor instead of RxJava, then you can give cassandra-java-driver-reactive-mapper a try.
The syntax is fairly simple and works in compile-time only.

On Hyperledger Fabric Context

I would appreciate some help with this small issue.
According to the comercial paper smart contract, present in Fabric-samples, one can define a custom Context, which allows handling logic across different transactions.
Can we define a variable in a Context, initialized as 0, and increment it at each transaction? I do not seem able to increment it, i.e., the counter always resets at each transation:
class CustomContext extends Context {
constructor() {
super();
this.comercialPaperList = new PaperList(this);
this.counter = 0;
}
generateLogId() {
return this.numberLogs++;
}
getLatestLogId() {
return this.numberLogs;
}
}
class MyContract extends Contract {
constructor() {
// Unique namespace when multiple contracts per chaincode file
super('...');
}
/**
* Define a custom context for a citius log
*/
createContext() {
return new CustomContext();
I have a test transaction which increments the counter:
async incrementC (ctx) {
let before = await ctx.getLatestLogId();
console.log(before);
let new = await ctx.generateLogId();
console.log(new);
console.log("============== after inc")
let after = await ctx.getLatestLogId();
console.log(after);
}
On the first time I execute the incrementC transaction, I obtain 0, 1, 1, as expected.
On the following times, I obtain exacly the same, as if context did not store the updates.
Any insights?
A Custom context has the same scope as a non custom context, it is the context for the currently executing transaction only. It is not able to span across multiple transaction requests. If the documentation implies this then I would suggest that there is something wrong with the documentation and a jira should be raised at https://jira.hyperledger.org to raise this as an issue.
So unfortunately what you are trying to do will not work.

how to add try catch exception for spring integration flow to achieve nested transactions

How to handle nested transactions in spring integration flow. Basically i have a process that fetches all the orders from database and process it order by order, in case of exception thrown on single order, all the orders processed are getting rolled back.
IntegrationFlows.from("perOrder")
.filter(Order.class, order -> order.getItems().size() > 0)
.handle(orderHandler, "handle") /*someway i way want to add try/catch for this method here so that
if handle method throws exception, want to suppress for that order and mark as failure only for that order */
.get();
public class OrderHandler {
#Transactional(propagation = Propagation.NESTED)
public handle() {
processing code
throw exception in case of any validation failure
}
}
For this purpose we provide an adviceChain to be injected into the endpoint of that handle():
.handle((GenericHandler<?>) (p, h) -> {
throw new RuntimeException("intentional");
}, e -> e.advice(retryAdvice()))
You can inject there any available Advice implementation: https://docs.spring.io/spring-integration/docs/current/reference/html/#message-handler-advice-chain, including TransactionInterceptor: https://docs.spring.io/spring-integration/docs/current/reference/html/#tx-handle-message-advice
The best way to have a try...catch semantics is with the ExpressionEvaluatingRequestHandlerAdvice. See its description in the Docs and also its JavaDocs.

Is there a way to ignore some entity properties when calling EdmxWriter.WriteEdmx

I am specifically using breezejs and the server code for breeze js converts the dbcontext into a form which is useable on the clientside using EdmxWriter.WriteEdmx. There are many properties which I have added JsonIgnore attributes to so that they don't get passed to the client side. However, the metadata that is generated (and passed to the clientside) from EdmxWriter.WriteEdmx still has those properties. Is there any additional attribute that I can add to those properties that I want ignored so that they are ignored by EdmxWriter.WriteEdmx? Or, would I need to make a separate method so as not to have any other unintended side effects.
You can sub-class your DbContext with a more restrictive variant that you use solely for metadata generation. You can continue to use your base context for persistence purposes.
The DocCode sample illustrates this technique with its NorthwindMetadataContext which hides the UserSessionId property from the metadata.
It's just a few extra lines of code that do the trick.
public class NorthwindMetadataContext : NorthwindContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
// Hide from clients
modelBuilder.Entity<Customer>().Ignore(t => t.CustomerID_OLD);
// Ignore UserSessionId in metadata (but keep it in base DbContext)
modelBuilder.Entity<Customer>().Ignore(t => t.UserSessionId);
modelBuilder.Entity<Employee>().Ignore(t => t.UserSessionId);
modelBuilder.Entity<Order>().Ignore(t => t.UserSessionId);
// ... more of the same ...
}
}
The Web API controller delegates to the NorthwindRepository where you'll see that the Metadata property gets metadata from the NorthwindMetadataContext while the other repository members reference an EFContextProvider for the full NorthwindContext.
public class NorthwindRepository
{
public NorthwindRepository()
{
_contextProvider = new EFContextProvider<NorthwindContext>();
}
public string Metadata
{
get
{
// Returns metadata from a dedicated DbContext that is different from
// the DbContext used for other operations
// See NorthwindMetadataContext for more about the scenario behind this.
var metaContextProvider = new EFContextProvider<NorthwindMetadataContext>();
return metaContextProvider.Metadata();
}
}
public SaveResult SaveChanges(JObject saveBundle)
{
PrepareSaveGuard();
return _contextProvider.SaveChanges(saveBundle);
}
public IQueryable<Category> Categories {
get { return Context.Categories; }
}
// ... more members ...
}
Pretty clever, eh?
Just remember that the UserSessionId is still on the server-side class model and could be set by a rogue client's saveChanges requests. DocCode guards against that risk in its SaveChanges validation processing.
You can sub-class your DbContext with a more restrictive variant that you use solely for metadata generation. You can continue to use your base context for persistence purposes.
The DocCode sample illustrates this technique with its NorthwindMetadataContext which hides the UserSessionId property from the metadata.
It's just a few extra lines of code that do the trick.
The Web API controller delegates to the NorthwindRepository where you'll see that the Metadata property gets metadata from the NorthwindMetadataContext while the other repository members reference an EFContextProvider for the full NorthwindContext.
Pretty clever, eh?
If you use the [NotMapped] attribute on a property, then it should be ignored by the EDMX process.

Resources