Creating TextIndex in Micronaut with reactive mongoDB - java

I am using reactive mongoDB with Micronaut application
implementation("io.micronaut.mongodb:micronaut-mongo-reactive")
Trying to create a TextIndex and search Free text functionality
public class Product {
#BsonProperty("id")
private ObjectId id;
private String name;
private float price;
private String description;
}
In spring data we have #TextIndexed(weight = 2) to create a TextIndex to the collection, what is the equivalent in the Micronaut application.

I'm afraid that Micronaut Data does not yet support automatic index creation based on annotations for MongoDB. Micronaut Data now simplifies only work with SQL databases.
But you can still create the index manually using MongoClient like this:
#Singleton
public class ProductRepository {
private final MongoClient mongoClient;
public ProductRepository(MongoClient mongoClient) {
this.mongoClient = mongoClient;
}
public MongoCollection<Product> getCollection() {
return mongoClient
.getDatabase("some-database")
.getCollection("product", Product.class);
}
#PostConstruct
public void createIndex() {
final var weights = new BasicDBObject("name", 10)
.append("description", 5);
getCollection()
.createIndex(
Indexes.compoundIndex(
Indexes.text("name"),
Indexes.text("description")
),
new IndexOptions().weights(weights)
)
.subscribe(new DefaultSubscriber<>() {
#Override
public void onNext(String s) {
System.out.format("Index %s was created.%n", s);
}
#Override
public void onError(Throwable t) {
t.printStackTrace();
}
#Override
public void onComplete() {
System.out.println("Completed");
}
});
}
}
You can of course use any subscriber you want. That anonymous class extending DefaultSubscriber is used here only for demonstration purpose.
Update: You can create indexes on startup for example by using #PostConstruct. It means to add all index creation logic in a method annotated by #PostConstruct in some repository or service class annotated by #Singleton, then it will be called after repository/service singleton creation.

Related

Call service when new data is inserted

I have this scheduler which is used to check for new data into DB table:
#Service
public class ReloadCache {
#Scheduled(fixedDelay = 1000)
public void reload() {
...... do something
}
}
......
#Service
public class LogicalClient {
final Map<String, Map<String, String>> map;
#PostConstruct
public void initializeBalances() {
............ map = new HashMap.......
}
#KafkaListener(......")
public void handle(....) {
.......read map here
}
}
Note that these two services are located in separate Java classes and packages.
When schedule runs and change is detected how how I can call again Java method initializeBalances annotated with #PostConstruct in order to generate again the map structure?
Inject your LogicalClient in your ReloadCache class and call that function like this:
#Service
public class ReloadCache {
private final LogicalClient logicalClient;
public ReloadCache(LogicalClient client) // Injection through constructor.
{
this.logicalClient = client;
}
#Scheduled(fixedDelay = 1000)
public void reload() {
...... do something
client.initializeBalances()
}
}
Both your classes are annotated with the #Service. So they are both Spring beans that can be injected wherever you find it suitable (as long as the receiving class is a bean itself).

Android Room implementation with background threading handling queries

I am recently trying to learn Android and I am very new to backend knowledge e.g. threading and stuff. I got Room figured out and try to integrate it with front end component. So, I am not worried how front end adapting the data I want it to present. I have the problem trying to design and implement the integration in a clean way using thread and trying to implement threading since I am new to it.
Here is my code.
Database.class
#Database(entities = {Groups.class, Member.class}, version = 1, exportSchema
= false)
public abstract class DatabaseConfig extends RoomDatabase {
private static final String DATABASE_NAME = "db";
private static DatabaseConfig INSTANCE;
public abstract GroupDao groupDao();
public abstract MemberDao memberDao();
public static DatabaseConfig getDatabase(final Context context) {
if (INSTANCE == null) {
synchronized (DatabaseConfig.class) {
if (INSTANCE == null) {
INSTANCE =
Room.databaseBuilder(context.getApplicationContext(),
DatabaseConfig.class, DATABASE_NAME)
.addCallback(DatabaseCallBack)
.build();
}
}
}
return INSTANCE;
}
private static RoomDatabase.Callback DatabaseCallBack =
new RoomDatabase.Callback(){
#Override
public void onOpen (#NonNull SupportSQLiteDatabase db){
super.onOpen(db);
}
};
}
GroupRepo.class
public class GroupRepo {
private final GroupDao groupDao;
//ExecutorService es = Executors.newSingleThreadExecutor();
public GroupRepo (Context context){
DatabaseConfig db = DatabaseConfig.getDatabase(context);
groupDao = db.groupDao();
}
public List<Groups> getAllGroups(){
/*
So my idea is to have some sort of threading implement from here
and use executor.run() to run my query and capture data
*/
}
}
Groups.class
#Dao
public interface GroupDao {
#Query("SELECT * from groups")
List<Groups> getAllGroups();
#Query("Select * from groups where groups.id = :groupsId")
GroupAllMembers getAllMember(int groupsId);
#Insert
void insert(Groups... groups);
#Delete
void delete(Groups groups);
}
I am not going to post my Entity class since my intention is not about that. I am fairly new to background threads. Please help and ideally provide some example to help me understand.
There are two ways to handle this: if you are doing the query on the database for UI view, I'd recommend your Day return LiveData> and then put that inside of a viewmodel. All of this is covered in Android docs.
If you are doing it in a service or don't want to interact with UI simply do this:
Thread(Runnable() {
#Override
public void run() {
// Do your stuff here with Room
}
}).start()

Objects Mirroring Others

Designing a new application, I have two sets of domain objects. One set mirrors the other and domain objects basically are paired up with similar attributes. When a domain object in the set A is created, updated, or deleted, a corresponding domain object in the set B will also be created, updated, or deleted. To reduce any coupling, I would like to separate those operations between a pair of domain objects. What will be a good mechanism to achieve this approach? I am thinking of using a messaging system. Will it work well for this case? I use Spring for this project.
Yes, using application events is a common solution for decreasing coupling between objects.
Actually spring already has builtin mechanism for that.
You might come up with something like:
#SpringBootApplication
public class So44490189Application {
public static void main(String[] args) {
SpringApplication.run(So44490189Application.class, args);
}
public static class UserCreatedEvent {
private final String email;
public UserCreatedEvent(String email) {
this.email = email;
}
}
#Service
public static class UserService {
#EventListener
public void handleUserCreatedEvent(UserCreatedEvent userCreatedEvent) {
System.out.println("Creating user " + userCreatedEvent.email);
}
}
#Service
public static class MemberService {
#EventListener
public void handleUserCreatedEvent(UserCreatedEvent userCreatedEvent) {
System.out.println("Creating member " + userCreatedEvent.email);
}
}
#Service
public static class OperationService {
private final ApplicationEventPublisher eventPublisher;
#Autowired
public OperationService(ApplicationEventPublisher eventPublisher) {
this.eventPublisher = eventPublisher;
}
public void createUser(String email) {
eventPublisher.publishEvent(new UserCreatedEvent(email));
}
}
#RestController
public static class OperationController {
private final OperationService operationService;
#Autowired
public OperationController(OperationService operationService) {
this.operationService = operationService;
}
#PostMapping
#ResponseStatus(HttpStatus.CREATED)
public void createUser(String email) {
operationService.createUser(email);
}
}
}
Usage
curl -XPOST 'localhost:8080?email=admin#localhost.localdomain'
Output
Creating member admin#localhost.localdomain
Creating user admin#localhost.localdomain
In this case creation user and members are mirrored.
One possible problem is transaction support and there is a couple of ways to deal with that. Spring has tools for it as well.

What is a common pattern for scheduled event handling in Spring?

In my application I need to add scheduled event checking and handling. When some business logic happened I need to create a posponed trigger, which should fire some actions through a particular time gap. For example:
If user posted photo, he should be notified if there is no likes under it within three days.
I feel that it should be a common pattern for such activities, relied on Spring framework features.
In your main config you need some like :
#Configuration
#EnableScheduling
public class HelloWorldConfig { ..}
Then in you bean where you want to schedule something :
#Scheduled(fixedRate=1000)
public void reload() { ..}
See http://docs.spring.io/spring/docs/current/spring-framework-reference/html/scheduling.html
Make sure you include the #EnableScheduling or equivalent if you're using XML config.
#Component
public class DemoExpirationEvent implements Runnable {
#Resource(name = "demoPhotoService")
private DemoExpirationService demoExpirationService;
#Resource(name = "demoExpirationTaskScheduler")
private TaskScheduler taskScheduler;
private Long id;
#Override
public void run() {
demoExpirationService.expiration(id);
}
public void schedule(Long id, Date dateToExpire){
this.id = id;
taskScheduler.schedule(this, dateToExpire);
}
}
#Service("demoPhotoService")
public class DemoPhotoServiceImpl implements DemoExpirationService, DemoPhotoService {
#Override
public void expiration(Long id) {
DemoPhoto photo = getPhoto(id);
photo.setExpirationDate(null);
savePhoto(photo);
notifyAuthorOfPhoto(id);
}
#Override
public void getPhoto(long id){
//some implementation
}
#Override
public void savePhoto(DemoPhoto photo){
//some implementation
}
#Override
public void notifyAuthorOfPhoto(long id){
//some implementation
}
}
public class DemoAddedPhotoActivity {
#Resource(name = "demoExpirationEvent")
private DemoExpirationEvent demoExpirationEvent;
#Resource(name = "demoPhotoService")
private DemoPhotoService demoPhotoService;
public void execute(long id) throws Exception {
DemoPhoto photo = demoPhotoService.getPhoto(id);
Date expirationDate = new Date(System.currentTimeMillis() + 30000000000L);
photo.setExpirationDate(expirationDate);
demoPhotoService.savePhoto(photo);
demoExpirationEvent.schedule(id, expirationDate);
}
}
register task scheduler in your applicationContext.xml
<beans xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task-4.1.xsd">
<task:scheduler id="demoExpirationTaskScheduler" pool-size="3"/>
And rest of beans too and call activity on adding photo (it can be controller method with execute like method

Spring MVC - race conditions?

Suppose I have the following Spring MVC controller
#RestController
#RequestMapping("/books")
public class BooksController {
#Autowired
private final BooksRepository booksRepository;
#RequestMapping(value="/search", method=RequestMethod.POST, consumes="application/json")
public Collection<Book> doSearch(#RequestBody final SearchCriteria criteria) {
return booksRepository.find(criteria);
}
}
and the following repository
#Service
public class BooksRepository {
#Autowired
private final JdbcTemplate jdbcTemplate;
#Autowired
private final SearchQueryBuilder searchQueryBuilder;
public Collection<BookLite> find(final SearchCriteria criteria) {
// TODO: will this cause race conditions?
searchQueryBuilder.clear().addKeywords(criteria.getKeywords());
final String query = searchQueryBuilder.buildQuery();
final Object[] params = searchQueryBuilder.buildParams();
return jdbcTemplate.query(query, params, new BookExtractor());
}
}
with the following SearchQueryBuilder implementation
#Component
public class SearchQueryBuilder {
private final List<String> keywords = new LinkedList<String>();
public SearchQueryBuilder clear() {
keywords.clear();
return this;
}
public SearchQueryBuilder addKeywords(final List<String> keywords) {
for (String keyword : keywords) {
add(keyword);
}
return this;
}
private SearchQueryBuilder add(final String keyword) {
keywords.add(keyword);
return this;
}
public String buildQuery() {
...
}
public Object[] buildParams() {
...
}
}
My concerns are the following. Since the SearchQueryBuilder class is not thread safe, injecting it this way will probably cause race conditions. What is a good way to handle this? Is it enough (and a good practice) to change the bean scope to e.g. request?
I would use SearchQueryBuilderFactory as a Spring bean, and create the SearchQueryBuilder instances on the fly.
I would avoid creating Spring beans that change state during the execution.
Your reliance on having them request-scoped makes your solution more fragile and error-prone, since the problem would reappear if you try to use it as Spring bean outside the web context.

Categories