Can we manage ScalarDB Transaction with #Transaction annotation? - scalardb

Spring can manage transactions using #Transaction annotation.
Can we manage ScalarDB transactions with #Transaction annotation?

Scalar DB doesn't support Spring annotations at the moment.

ScalarDB 3.8 was released yesterday and it supports Spring Data integration. With the integration, users can use ScalarDB via Spring Data JDBC API like the following example:
#Repository
public interface NorthAccountRepository
extends PagingAndSortingRepository<NorthAccount, Integer>,
ScalarDbHelperRepository<NorthAccount> {
#Transactional
default void transferToSouthAccount(
#Nonnull SouthAccountRepository southAccountRepository,
int fromId, int toId, int value) {
NorthAccount fromEntity =
findById(fromId).orElseThrow(() -> new AssertionError("Not found: " + fromId));
SouthAccount toEntity =
southAccountRepository
.findById(toId)
.orElseThrow(() -> new AssertionError("Not found: " + toId));
update(new NorthAccount(fromEntity.id, fromEntity.balance - value));
southAccountRepository.update(new SouthAccount(toEntity.id, toEntity.balance + value));
}
#Transactional
default void deleteAfterSelect(int id) {
findById(id).ifPresent(this::delete);
}
}
It also provides explicit insert(T) and update(T) APIs in addition to the existing save(T).
The integration is available under the commercial license.

Related

View Single Record in Spring Boot and Mongo

I'm trying to develop a simple crud application using Spring and Mongodb.
When I'm trying to develop view single data function, I get no error.
But it return value as null when I try in Postman.
Could you please help me to find what is the wrong with my code?
Controller
#GetMapping("/patient/{id}")
public Optional<Patients> findTicketById(#PathVariable("id") #NotNull String id){
System.out.println(id);
return patientRepository.findById(id);
}
Repository
#Repository
public interface PatientRepository extends MongoRepository<Patients, Long> {
Optional<Patients> findById(String id);
}
You can use ifPresentOrElse , check for the usages :
Functional style of Java 8's Optional.ifPresent and if-not-Present?

Axon Framework - Configuring Multiple EventStores in Axon Configuration

We are having an usecase wherein each aggregate root should have different eventstores. We have used the following configuration where currently , we have only one event-store configured as below
#Configuration
#EnableDiscoveryClient
public class AxonConfig {
private static final String DOMAIN_EVENTS_COLLECTION_NAME = "coll-capture.domainEvents";
//private static final String DOMAIN_EVENTS_COLLECTION_NAME_TEST =
//"coll-capture.domainEvents-test";
#Value("${mongodb.database}")
private String databaseName;
#Value("${spring.application.name}")
private String appName;
#Bean
public RestTemplate restTemplate() {
CloseableHttpClient httpClient = HttpClientBuilder.create().build();
HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new
HttpComponentsClientHttpRequestFactory(httpClient);
return new RestTemplate(clientHttpRequestFactory);
}
#Bean
#Profile({"uat", "prod"})
public CommandRouter springCloudHttpBackupCommandRouter(DiscoveryClient discoveryClient,
Registration localInstance,
RestTemplate restTemplate,
#Value("${axon.distributed.spring-
cloud.fallback-url}") String messageRoutingInformationEndpoint) {
return new SpringCloudHttpBackupCommandRouter(discoveryClient,
localInstance,
new AnnotationRoutingStrategy(),
serviceInstance -> appName.equalsIgnoreCase(serviceInstance.getServiceId()),
restTemplate,
messageRoutingInformationEndpoint);
}
#Bean
public Repository<TestEnquiry> testEnquiryRepository(EventStore eventStore) {
return new EventSourcingRepository<>(TestEnquiry.class, eventStore);
}
#Bean
public Repository<Test2Enquiry> test2enquiryRepository(EventStore eventStore) {
return new EventSourcingRepository<>(Test2Enquiry.class, eventStore);
}
#Bean
public EventStorageEngine eventStorageEngine(MongoClient client) {
MongoTemplate mongoTemplate = new DefaultMongoTemplate(client, databaseName)
.withDomainEventsCollection(DOMAIN_EVENTS_COLLECTION_NAME);
return new MongoEventStorageEngine(mongoTemplate);
}
}
Now , We want to configure "DOMAIN_EVENTS_COLLECTION_NAME_TEST"(just for example) as well in EventStorageEngine. How we can achieve the same support for multiple event-stores and select the tracking process as which collection they should be part of
If you are going the route of segregating the event streams, then combining them from an event handling perspective could become a necessity indeed. Especially when having several bounded contexts, segregating the event streams into distinct storage solutions is reasonable.
If you want to define which [message source / event store] is used by a TrackingEventProcessor, you will have to deal with the EventProcessingConfigurer. More specifically, you should invoke the EventProcessingConfigurer#registerTrackingEventProcessor(String, Function<Configuration, StreamableMessageSource<TrackedEventMessage<?>>>) method. The first String parameter is the name of the processor you want to configure as being "tracking". The second parameter defines a Function which gives you the message source to be used by this TrackingEventProcessor (TEP). It is here where you should provide the event store you want this TEP to ingest events from.
Pairing them up at a later stage could also occur of course, which is also supported by Axon Framework. This boils down to a specific form of StreamableMessageSource implementation.
More specifically, you can use the MultiStreamableMessageSource, where you can connect any number of StreamableMessageSources together.
Note that Axon's EmbeddedEventStore is in essence an implementation of a StreamableMessageSource. Once the MultiStreamableMessageSource, you will have to specify it as the messageSource for your TrackingEventProcessors of course.
Last note, know that this solution can only be used when you are using TrackingEventProcessors, as those are the only Event Processors provided by Axon ingesting a StreamableMessageSource as the source for it's events.

How to inject spring aop advice for MongoDb call?

I am new to Spring Aop, but I have case to implement AOP advice for a mongo db call(monog db update). I am trying in different way but getting 'Point cut not well formed' error or 'warning no match for this type name: arg string [Xlint:invalidAbsoluteTypeName]'(even if I give absolute name of the argument). Anyone can help on this as how to inject advice for mongo db update call?
#Aspect
#Component
public class DBStatsLoggerAspect {
private static final Logger log = LoggerFactory
.getLogger(DBStatsLoggerAspect.class);
private static final Document reqStatsCmdBson = new Document(
"getLastRequestStatistics", 1);
private DbCallback<Document> requestStatsDbCallback = new DbCallback<Document>() {
#Override
public Document doInDB(MongoDatabase db) throws MongoException,
DataAccessException {
return db.runCommand(reqStatsCmdBson);
}
};
#After("execution( public * com.mongodb.client.MongoCollection.*(..)) && args(org.bson.conversions.Bson.filter,..)")
public void requestStatsLoggerAdvice(JoinPoint joinPoint) {
MongoTemplate mongoTemplate = (MongoTemplate) joinPoint.getTarget();
log.info(mongoTemplate.execute(requestStatsDbCallback).toJson());
}
}
Actual db call method where I need to inject advice:(filter, updatePart all are org.bson.conversions.Bson data type) and here 'collection' is com.mongodb.client.MongoCollection.collection
Document result = collection.findOneAndUpdate(filter, updatePart, new FindOneAndUpdateOptions().upsert(false));
I am not a Spring or MongoDB user, just an AOP expert. But from what I see I am wondering:
You are intercepting execution(public * com.mongodb.client.MongoCollection.*(..)), so joinPoint.getTarget() is a MongoCollection type. Why do you think you can cast it to MongoTemplate? That would only work if your MongoCollection happened to be a MongoTemplate subclass. To me this looks like a bug.
Class MongoCollection is not a Spring component but a third-party class. Spring AOP can only intercept Spring component calls by means of creating dynamic proxies for those components and adding aspect interceptors to said proxies. so no matter how correct or incorrect your pointcut, it should never trigger.
What you can do instead is switch from Spring AOP to full-blown AspectJ. The standard way to do this is to activate AspectJ load-time weaving (LTW).

How to generate pretty print docs while using spring cloud contract

Without introducing spring cloud contract, I customized the configuration of restdocs as below,
#Rule
public JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation();
protected WebTestClient http;
#Autowired
private ApplicationContext context;
/**
* setup.
*/
#Before
public void before() {
this.http = WebTestClient.bindToApplicationContext(context)
.configureClient()
.baseUrl("http://theserver")
.filter(WebTestClientRestDocumentation
.documentationConfiguration(this.restDocumentation)
.operationPreprocessors()
.withRequestDefaults(prettyPrint())
.withResponseDefaults(prettyPrint())
)
.build();
}
However while using spring restdocs and cloud contract together, I have to use the annotation to enable rest docs and cloud contract,
#AutoConfigureRestDocs(uriHost = "theserver", uriPort = 80)
#AutoConfigureWebTestClient
public abstract class BaseTest {
Any advice how to generate pretty print docs while generating cloud contract stubs?
What you can do is not to use the #AutoConfigureRestDocs but use the API to pass to WebTestClientRestDocumentation.documentationConfiguration(...) the .snippets().withAdditionalDefaults(new WireMockSnippet()) line. That way by default you will start producing WireMock snippets and all of your previous configuration will not be discarded.

How to choose a Spring #Query annotation to suit the DB (e.g. HSQLDB, Postgres)?

Say I have this annotated Java code:
#Transactional
public interface EventRepository extends JpaRepository<Event, Long> {
#Query("from Event where path like ?1% and date(start_time)=CURRENT_DATE")
Stream<Event> findAllChildrenToday(String path);
This works for Postgres. However, when running unit tests I want to use an in-memory database such as HSQLDB. Unfortunately the SQL date(...) command doesn't work on HSQLDB, so I really need something that changes query according to the database like the following in which I've made up an imaginary "db=" tag:
#Query(db="Postgres", "from Event where path like ?1% and date(start_time)=CURRENT_DATE")
#Query(db="HSQLDB", "from Event where path like ?1% and start_time >= CURRENT_DATE and (start_time < CURRENT_DATE + 1)")
Stream<Event> findAllChildrenToday(String path);
How do I do this for real?
I'm not too familiar with Spring so please be fairly detailed in your answers. Thanks.
You can make the following trick with Spring profiles:
#NoRepositoryBean
public interface EventRepo extends JpaRepository<Event, Long> {
Stream<Event> findAllChildrenToday(String path);
}
#Profile("postgres")
public interface PostgresRepo extends EventRepo {
#Override
#Query(/* a postgres specific query */)
Stream<Event> findAllChildrenToday(String path);
}
#Profile("hsqldb")
public interface HsqldbRepo extends EventRepo {
#Override
#Query(/* a hsqldb specific query */)
Stream<Event> findAllChildrenToday(String path);
}
Then in your service (or controller):
#Service
public class EventService {
#Autowired
private EventRepo eventRepo;
//...
}
In the application.properties file you set 'postgres' profile (this profile will be used by default in the production):
spring.profiles.active=postgres
And in your IDE you set 'hsqldb' profile: -Dspring.profiles.active=hsqldb (as JVM option).
Thanks to this the repo injection will depend on the used Spring profile.