Check if object is exists in room database android java - java

I am new at the room database in android and I want to insert data into the room, but before inserting I want to check if the item already exists in the database or not. I am using these codes(News and Article are the same it is just naming problem):
My Dao
package com.example.newsapp.models;
import androidx.lifecycle.LiveData;
import androidx.room.Dao;
import androidx.room.Insert;
import androidx.room.OnConflictStrategy;
import androidx.room.Query;
import com.example.newsapp.operations.Article;
import java.util.List;
#Dao
public interface SavedNewsDAO {
#Insert(onConflict = OnConflictStrategy.REPLACE)
void insert(Article article);
#Query("DELETE FROM saved_articles")
void deleteAll();
#Query("DELETE FROM saved_articles where id =:id ")
void removeNews(int id);
#Query("SELECT * FROM saved_articles")
LiveData<List<Article>> getAll();
#Query("select Count() from saved_articles where title =:title and content =:content and description =:description")
int checkArticle(String title, String content, String description);
}
I want to get number of items in the database with checkArticle method.
My Repository
package com.example.newsapp.models;
import android.app.Application;
import androidx.lifecycle.LiveData;
import com.example.newsapp.operations.Article;
import java.util.List;
public class SavedArticlesRepository {
private final LiveData<List<Article>> allArticles;
private final SavedNewsDAO savedNewsDAO;
SavedArticlesRepository(Application application) {
SavedNewsRoomDatabase db = SavedNewsRoomDatabase.getDatabase(application);
savedNewsDAO = db.savedNewsDAO();
allArticles = savedNewsDAO.getAll();
}
LiveData<List<Article>> getAllArticles() {
return allArticles;
}
void insert(Article article) {
SavedNewsRoomDatabase.databaseWriterExecutor.execute(() -> savedNewsDAO.insert(article));
}
void checkItem(Article article) {
SavedNewsRoomDatabase.databaseWriterExecutor.execute(() -> {
savedNewsDAO.checkArticle(article.title, article.content, article.description);
});
}
}
and this is my View Model
package com.example.newsapp.models;
import android.app.Application;
import androidx.lifecycle.AndroidViewModel;
import androidx.lifecycle.LiveData;
import com.example.newsapp.operations.Article;
import java.util.List;
public class SavedNewsViewModel extends AndroidViewModel {
private final SavedArticlesRepository savedArticlesRepository;
private final LiveData<List<Article>> allArticles;
public SavedNewsViewModel(Application application) {
super(application);
savedArticlesRepository = new SavedArticlesRepository(application);
allArticles = savedArticlesRepository.getAllArticles();
}
public LiveData<List<Article>> getAllArticles() {
return allArticles;
}
public void insert(Article article) {
savedArticlesRepository.insert(article);
}
public void checkArticle(Article article) {
savedArticlesRepository.checkItem(article);
}
}
The problem is that I can't imagine how can I use checkArticle method in ViewModel and Repository classes like getAll method. As I understand I must chain these methods to each-others. And I want to check in this method:
savedNewsViewModel = new ViewModelProvider(this).get(SavedNewsViewModel.class);
saveArticleButton.setOnClickListener(v -> {
Article article = new Article();
article.title = intent.getStringExtra("title");
article.description = intent.getStringExtra("description");
article.content = intent.getStringExtra("content");
article.urlToImage = intent.getStringExtra("image");
savedNewsViewModel.insert(article);
Toast.makeText(this, "Article saved successfully", Toast.LENGTH_SHORT).show();
});
I have looked other questions, but I couldn't get it

You need to observe the value which you get from your checkArticle method.
Use MutableLiveData in the following way:
public class SavedArticlesRepository {
....
LiveData<Integer> checkItem(Article article) {
MutableLiveData<Integer> data = MutableLiveData();
SavedNewsRoomDatabase.databaseWriterExecutor.execute(() -> {
int count = savedNewsDAO.checkArticle(article.title, article.content, article.description);
data.postValue(count);
});
return data;
}
}
Now in your viewmodel, also extend the checkArticle with LiveData
public LiveData<Integer> checkArticle(Article article) {
return savedArticlesRepository.checkItem(article);
}
In your fragment or activity observe this method:
saveArticleButton.setOnClickListener(v -> {
Article article = new Article();
article.title = intent.getStringExtra("title");
article.description = intent.getStringExtra("description");
article.content = intent.getStringExtra("content");
article.urlToImage = intent.getStringExtra("image");
savedNewsViewModel.checkArticle.observe(getViewLifeCycleOwner(), new Observer{ count ->
if(count > 0){
Toast.makeText(this, "Article already exists", Toast.LENGTH_SHORT).show();
} else {
savedNewsViewModel.insert(article);
Toast.makeText(this, "Article saved successfully", Toast.LENGTH_SHORT).show();
}
});
});
I haven't tested this code, as I don't work with Java anymore. But should work fine.
If I can suggest, I'd say learn Kotlin and coroutines. This stuff is so much easier when you're using Kotlin and coroutines.
Leave a comment if you need any more help with this.

Related

Insert into local sql lite databse recived Push Notification from Firebase Cloud messeging

I try to write to local sql lite database in onMessageReceived method in class Notification witch extends FirebaseMessagingService. But no luck with this.The notification is recieved to the phone its get the data I handle the data parameter in Main Activity. But the actual insert statment is not inserting into the database.Any help will be helpful.Thank you
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
// Insert into databse here
}
I) onMessageReceived method works only on foreground so you can't catch all message from firebase using this method.
II) If you want catch background notification you can do like this, but this method works when user click to notification:
1. On MainActivity.java file this file must be first launcher file, add this code:
#Override
protected void onCreate(Bundle savedInstanceState) {
Bundle bundle = getIntent().getExtras();
if (bundle != null) {
//bundle must contain all info sent in "data" field of the notification
if (bundle.get("data") != null) {
Utils.saveToLocalDB(data,context);
}
}
}
2. In FirebaseNotificationService.java file add this code:
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
if (remoteMessage.getNotification() != null) {
String notifText = remoteMessage.getNotification().getBody() + " / " + remoteMessage.getNotification().getTitle()
Utils.saveToLocalDB(notifText, context);
}
}
3) Install this dependencies, add this to app's build.gradle
def room_version = "2.4.3"
implementation "androidx.room:room-runtime:$room_version"
annotationProcessor "androidx.room:room-compiler:$room_version"
If you need more information about room database click here
4) Create NotifModel.java class file and add this code in that file:
import androidx.room.ColumnInfo;
import androidx.room.Entity;
import androidx.room.PrimaryKey;
#Entity
public class NotifModel {
#PrimaryKey
public int uid;
#ColumnInfo(name = "message")
private String message;
public NotifModel(String message) {
this.message = message;
}
public int getUid() {
return uid;
}
public void setUid(int uid) {
this.uid = uid;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
5) Create NotifDao.java interface file and add this code into that file:
import androidx.room.Dao;
import androidx.room.Delete;
import androidx.room.Insert;
import androidx.room.Query;
import java.util.List;
#Dao
public interface NotifDao {
#Query("SELECT * FROM notifmodel")
List<NotifDao> getAll();
#Insert
void insertAll(NotifModel notifModel);
#Delete
void delete(NotifModel notifModel);
}
6) Create NotifDatabase.java abstract class and add this code into that file:
import androidx.room.Database;
import androidx.room.RoomDatabase;
#Database(entities = {NotifModel.class}, version = 1)
public abstract class NotifDatabase extends RoomDatabase {
public abstract NotifDao notifDao();
}
7) Create Utils.java class and add this code into that file:
public class Utils {
public static void saveToLocalDB(String message,Context context){
NotifDatabase db= Room.databaseBuilder(context,
NotifDatabase.class, "notif_db").allowMainThreadQueries().fallbackToDestructiveMigration().build();
NotifDao notifDao=db.notifDao();
notifDao.insertAll(new NotifModel(message));
}
}
8) When you send notification from firebase dashboard or backend you must add additional data called with "data". This "data" include notification title and body in one string variable.
9) Sqlite is deprecated so I use Room database

How to manipulate a list attribute inside Mono as a flux?

I am new to project reactor and I am trying to manipulate some fields in a list as Flux inside a Mono.
So I have Mono<Basket> with an attribute called lines which is a List<Line>.
Then, for every line I have to call two external services to get some additional info.
Here is my code:
Mono<Basket> basketMono = //this doesn't work cause I map it to a Flux
Mono.just(basket)
.flatMapIterable(Basket::getLines)
.parallel(...)
.runOn(...)
.map((line) -> {
line.setInfo1(externalService1.getInfo());
line.setInfo2(externalService2.getInfo());
return line;
});
My main problem here is that I don't know how to set this additional info to the lines and keep the original object so the method that holds this code can return the Mono<Basket> with all the additional info setted.
I am struggling with this. Is this approach right? Some help would be more than appreciate.
A simple solution is you dont flatmap the lines, because it will create a new publisher with n element (and type line). Within flatmap, you can start another publisher, which goes to services, set data and then you can return the original object.
Mono<Basket> basketMono = Mono.just(basket)
.flatMap(b ->
Flux.fromIterable(b.items)
.flatMap(this::callService1)
.flatMap(this::callService2)
.then(Mono.just(b))
);
I suppose your external service calls are reactive, something like this:
Mono<Item> callService1(Item item) {
return mockService1().zipWith(Mono.just(item))
.map(it -> {
var result = it.getT2();
result.setInfo1(it.getT1());
return result;
});
}
Mono<String> mockService1() {
return Mono.just("some data " + ThreadLocalRandom.current().nextInt(100)).delayElement(Duration.ofMillis(100));
}
Note that flatMap will automatically subscribe to the inner publisher.
Also I've created a simple example, you can test:
import org.junit.jupiter.api.Test;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;
import java.time.Duration;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
public class Example {
class Item {
String info1;
String info2;
public void setInfo1(String info1) {
this.info1 = info1;
}
public void setInfo2(String info2) {
this.info2 = info2;
}
public String getInfo1() {
return info1;
}
public String getInfo2() {
return info2;
}
}
class Basket {
String user;
List<Item> items;
public Basket(String user, List<Item> items) {
this.user = user;
this.items = items;
}
}
Mono<String> mockService1() {
return Mono.just("some data " + ThreadLocalRandom.current().nextInt(100)).delayElement(Duration.ofMillis(100));
}
Mono<String> mockService2() {
return Mono.just("some other data " + ThreadLocalRandom.current().nextInt(1000)).delayElement(Duration.ofMillis(100));
}
Mono<Item> callService1(Item item) {
return mockService1().zipWith(Mono.just(item))
.map(it -> {
var result = it.getT2();
result.setInfo1(it.getT1());
return result;
});
}
Mono<Item> callService2(Item item) {
return mockService2().zipWith(Mono.just(item))
.map(it -> {
var result = it.getT2();
result.setInfo1(it.getT1());
return result;
});
}
#Test
public void testBasket() {
var basket = new Basket("first", List.of(new Item(), new Item(), new Item()));
Mono<Basket> basketMono = Mono.just(basket)
.flatMap(b ->
Flux.fromIterable(b.items)
.flatMap(this::callService1)
.flatMap(this::callService2)
.then(Mono.just(b))
);
StepVerifier.create(basketMono)
.expectNextMatches(b -> b.items.get(0).info1 != null)
.verifyComplete();
}
}

How can we use lagom's Read-side processor with Dgraph?

I am a newbie to lagom and dgraph. And I got stuck to how to use lagom's read-side processor with Dgraph. Just to give you an idea following is the code which uses Cassandra with lagom.
import akka.NotUsed;
import com.lightbend.lagom.javadsl.api.ServiceCall;
import com.lightbend.lagom.javadsl.persistence.cassandra.CassandraSession;
import java.util.concurrent.CompletableFuture;
import javax.inject.Inject;
import akka.stream.javadsl.Source;
public class FriendServiceImpl implements FriendService {
private final CassandraSession cassandraSession;
#Inject
public FriendServiceImpl(CassandraSession cassandraSession) {
this.cassandraSession = cassandraSession;
}
//Implement your service method here
}
Lagom does not provide out-of-the-box support for Dgraph. If you have to use Lagom's Read-Side processor with Dgraph, then you have to use Lagom's Generic Read Side support. Like this:
/**
* Read side processor for Dgraph.
*/
public class FriendEventProcessor extends ReadSideProcessor<FriendEvent> {
private static void createModel() {
//TODO: Initialize schema in Dgraph
}
#Override
public ReadSideProcessor.ReadSideHandler<FriendEvent> buildHandler() {
return new ReadSideHandler<FriendEvent>() {
private final Done doneInstance = Done.getInstance();
#Override
public CompletionStage<Done> globalPrepare() {
createModel();
return CompletableFuture.completedFuture(doneInstance);
}
#Override
public CompletionStage<Offset> prepare(final AggregateEventTag<FriendEvent> tag) {
return CompletableFuture.completedFuture(Offset.NONE);
}
#Override
public Flow<Pair<FriendEvent, Offset>, Done, ?> handle() {
return Flow.<Pair<FriendEvent, Offset>>create()
.mapAsync(1, eventAndOffset -> {
if (eventAndOffset.first() instanceof FriendCreated) {
//TODO: Add Friend in Dgraph;
}
return CompletableFuture.completedFuture(doneInstance);
}
);
}
};
}
#Override
public PSequence<AggregateEventTag<FriendEvent>> aggregateTags() {
return FriendEvent.TAG.allTags();
}
}
For FriendEvent.TAG.allTags(), you have to add following code in FriendEvent interface:
int NUM_SHARDS = 20;
AggregateEventShards<FriendEvent> TAG =
AggregateEventTag.sharded(FriendEvent.class, NUM_SHARDS);
#Override
default AggregateEventShards<FriendEvent> aggregateTag() {
return TAG;
}
I hope this helps!

How can we store the timestamp into the list when log4j messages are stored into the list and fetched into a swt table created

I also need to store the time stamp inside the list when the log message is pushed into the list.So how can we get the timestamp and push into the list.I am pushing the logs into the list as follows
import java.util.ArrayList;
import java.util.List;
import org.apache.log4j.RollingFileAppender;
//import org.apache.log4j.spi.LoggingEvent;
import org.apache.log4j.spi.LoggingEvent;
public class Listappender extends RollingFileAppender {
private List<LoggingEvent> events = new ArrayList<LoggingEvent>();
static List<String> clone = new ArrayList<String>();
#Override
public synchronized void doAppend(LoggingEvent event) {
//System.out.println("hi....");
//events.clear();
events.add(event);
super.doAppend(event);
clone.clear();
clone.add((String) event.getMessage());
//getEvents();
/*
for (int j = 0; j < events.size(); j++){
System.out.println(events.get(j));
System.out.println(j);
}*/
}
public List<String> getEntries()
{
return clone;
}
}
See how to create timestamp Java Timestamp - How can I create a Timestamp with the date 23/09/2007?
And you can simply do this
clone.add(timestamp.toString() + event.getMessage());
Just keep the LoggingEvent s in a list. You don't have to get the message and save it in a different list. The LoggingEvent has a public final long getTimeStamp() method to supply the time. Try using this code:
import java.util.ArrayList;
import java.util.List;
import org.apache.log4j.RollingFileAppender;
import org.apache.log4j.spi.LoggingEvent;
public class ListAppender extends RollingFileAppender {
private final List<LoggingEvent> events = new ArrayList<LoggingEvent>();
#Override
public synchronized void doAppend(LoggingEvent event) {
events.add(event);
super.doAppend(event);
}
public synchronized List<LoggingEvent> getLoggingEvents() {
List<LoggingEvent> clone = new ArrayList<>(events);
events.clear();
return clone;
}
}

How to use org.hibernate.action.spi.AfterTransactionCompletionProcess?

I found this class that I really want to use:
org.hibernate.action.spi.AfterTransactionCompletionProcess -
http://docs.jboss.org/hibernate/orm/3.6/javadocs/org/hibernate/action/AfterTransactionCompletionProcess.html
Basically, I'd like some custom logic to happen after the transaction is committed. But I cannot for the life of me figure out how to use this thing.
Where do I specify this interface? Any examples would be awesome.
Found an example in the Hibernate 4.3's unit test code base:
org.hibernate.envers.test.integration.basic.RegisterUserEventListenersTest
Shows exactly what I was looking for:
package org.hibernate.envers.test.integration.basic;
import org.hibernate.Session;
import org.hibernate.action.spi.AfterTransactionCompletionProcess;
import org.hibernate.action.spi.BeforeTransactionCompletionProcess;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.envers.internal.tools.MutableInteger;
import org.hibernate.envers.test.BaseEnversFunctionalTestCase;
import org.hibernate.envers.test.entities.StrTestEntity;
import org.hibernate.event.service.spi.EventListenerRegistry;
import org.hibernate.event.spi.EventType;
import org.hibernate.event.spi.PostInsertEvent;
import org.hibernate.event.spi.PostInsertEventListener;
import org.hibernate.persister.entity.EntityPersister;
import org.junit.Assert;
import org.junit.Test;
import org.hibernate.testing.TestForIssue;
/**
* #author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/
public class RegisterUserEventListenersTest extends BaseEnversFunctionalTestCase {
#Override
protected Class<?>[] getAnnotatedClasses() {
return new Class<?>[] {StrTestEntity.class};
}
#Test
#TestForIssue(jiraKey = "HHH-7478")
public void testTransactionProcessSynchronization() {
final EventListenerRegistry registry = sessionFactory().getServiceRegistry()
.getService( EventListenerRegistry.class );
final CountingPostInsertTransactionBoundaryListener listener = new CountingPostInsertTransactionBoundaryListener();
registry.getEventListenerGroup( EventType.POST_INSERT ).appendListener( listener );
Session session = openSession();
session.getTransaction().begin();
StrTestEntity entity = new StrTestEntity( "str1" );
session.save( entity );
session.getTransaction().commit();
session.close();
// Post insert listener invoked three times - before/after insertion of original data,
// revision entity and audit row.
Assert.assertEquals( 3, listener.getBeforeCount() );
Assert.assertEquals( 3, listener.getAfterCount() );
}
private static class CountingPostInsertTransactionBoundaryListener implements PostInsertEventListener {
private final MutableInteger beforeCounter = new MutableInteger();
private final MutableInteger afterCounter = new MutableInteger();
#Override
public void onPostInsert(PostInsertEvent event) {
event.getSession().getActionQueue().registerProcess(
new BeforeTransactionCompletionProcess() {
#Override
public void doBeforeTransactionCompletion(SessionImplementor session) {
beforeCounter.increase();
}
}
);
event.getSession().getActionQueue().registerProcess(
new AfterTransactionCompletionProcess() {
#Override
public void doAfterTransactionCompletion(boolean success, SessionImplementor session) {
afterCounter.increase();
}
}
);
}
#Override
public boolean requiresPostCommitHanding(EntityPersister persister) {
return true;
}
public int getBeforeCount() {
return beforeCounter.get();
}
public int getAfterCount() {
return afterCounter.get();
}
}
}

Categories

Resources