I have a Java, Spring application where I schedule some report jobs. The component looks like this:
#Component
public class RegisterReportSchedules implements ApplicationListener<ContextRefreshedEvent> {
#Autowired
private ThreadPoolTaskScheduler ts;
private List<String> reportSchedules; //contains list of report schedules
#Autowired
private SomeTask sometask;
#Override
public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
reportSchedules.forEach((String schedule) -> {
ReportSchedule reportSchedule = new ReportSchedule(schedule,
propertiesUtil.getProperty(schedule + "." + Constants.CRON));
ts.schedule(new ReportTask(reportSchedule),
new CronTrigger(reportSchedule.getCronExpression()));
});
}
class ReportTask implements Runnable {
private ReportSchedule schedule;
public ReportTask(ReportSchedule schedule) {
this.schedule = schedule;
}
#Override
public void run() {
sometask.process(schedule);
}
}
}
Say I have 5 reportSchedules to process. After all 5 ReportTasks have been completed, I need to write into a db table one entry to say all report task completed.
But how can I track this information about each report schedule is completed in my application?
Do I need to write to database table for each schedule completed or is there a better alternative within Spring that will trigger a notification event of some sort which I can then use to write the ALL COMPLETED event to the table? Appreciate if some answers with examples are given.
Since you don't need to track the reportSchedules, I'd be tempted to do something like:
Move to use a Queue so that the Strings are removed when you poll.
Track the number of tasks that you submit. (*)
Add a custom ApplicationEvent type of ReportScheduleProcessedEvent (or similar) and publish one of these (to Spring's ApplicationEventPublisher) at the end of the ReportTask's run method.
Add a new ApplicationListener for this type, which waits until it has received as many events as you tracked in (*); and then publishes something to the database.
I'm afraid I haven't provided any code here, since you might or might not need to care about thread-safety at a bunch of points above, and handling this appropriately might not be trivial.
Edit; per comment asking for a sample. I'll assume you're using at least spring 4.3.
Edit Edit: per more comments.
abstract class ReportScheduleEvent extends ApplicationEvent { ... }
public class IncomingReportCompletionEvent
extends ReportScheduleEvent {
private final int eventsToExpect;
// ...
}
public class ReportCompletionEvent extends ReportSchedulingEvent {
// ...
}
public class YourListener
implements ApplicationListener<ReportSchedulingEvent> {
private final DatabaseWriter dbWriter;
private volatile int expectedEvents = 0;
public void onApplicationEvent(final ReportSchedulingEvent event) {
if (event instanceof IncomingReportCompletionEvent) {
this.expectedEvents =
((IncomingReportCompletionEvent) event)
.getExpectedEventCount();
} else {
this.expectedEvents--;
if (this.expectedEvents == 0) {
this.dbWriter.doYourThing();
}
}
}
}
Related
Hopefully I can make some sense, I've never done this particular task before.
I have an application where I want to create a bean on startup that has a scheduled task that runs every 30 minutes and updates a Map that is used by all sessions in the application. My initial thought was to create an ApplicationScoped bean for this task.
So the idea is this:
User A logs in. Stores value in his Map.
User B logs in. Stores value in his Map.
Process runs, updates all values in map.
User B and A will check their value constantly throughout the session.
Logout, remove value from map.
So right now it looks like this:
#ManagedBean(eager=true, name="monitor")
#ApplicationScoped
public class MyMonitor implements Serializable {
private static final long serialVersionUID = -1L;
private ScheduledExecutorService scheduler;
private HashMap<Integer, String> myDict;
#PostConstruct
public void init() {
myDict = new HashMap<Integer, String>();
myDict.put(1, "a");
myDict.put(2, "b");
myDict.put(3, "c");
scheduler = Executors.newSingleThreadScheduledExecutor();
scheduler.scheduleAtFixedRate(new SomeDailyJob(), 0, 30, TimeUnit.SECONDS);
}
#PreDestroy
public void destroy() {
scheduler.shutdownNow();
}
public class SomeDailyJob implements Runnable {
#Override
public void run() {
System.out.println("hello world");
}
}
public HashMap<Integer, String> getMyDict() {
return myDict;
}
public void setMyDict(HashMap<Integer, String> myDict) {
this.myDict = myDict;
}
}
In another class, I need to somehow retrieve the value from myDict based on key (this class is in the DAO layer, it is not a managed bean). I tried to instantiate this bean in that class:
public class MyDAO {
#ManagedProperty(value="#{myMonitor}")
private MyMonitor monitor;
}
And got:
WARNING: The web application [app] is still processing a request that has yet to finish
My questions are this:
Should I actually use an ApplicationScoped bean for this problem?
I do not have EJB.
I know I haven't added the synchronicity yet,
but is this safe? Can this actually work?
You can use a java.util.Timer for this. Define a class
import java.util.TimerTask;
public class Monitor extends TimerTask {
#Override
public void run() {
// do something
}
}
then your class may be refactored to something like (I removed other code to keep just the idea)
#ManagedBean(eager=true, name="monitor")
#ApplicationScoped
public class MyMonitor implements Serializable {
//runs as daemon thread
private final Timer timer = new Timer(true);
private Monitor monitor = new Monitor();
#PostConstruct
public void init() {
// period are in milliseconds
timer.scheduleAtFixedRate(monitor, 0, 30*1000);
}
#PreDestroy
public void destroy() {
timer.cancel();
}
}
This will help you also to move most of the update logic in the Monitor.run() separating it from the scheduler logic. I hope it helps.
Everywhere the same information, long time operation need to run in other thread, different than UI thread, for example - operation with Database.
...and its true, if I try to save something into DB I got:
Cannot access database on the main thread since it may potentially
lock the UI for a long period of time.
Here is my question, why I'm able get all data from database from UI ? :)
(my database didn't have .allowMainThreadQueries()"
This is a little modified code from google documentation:
ViewModel:
public class LocationsViewModel extends AndroidViewModel {
private LocationRepository locationRepository;
private LiveData<List<LocationModel>> allLocationsLiveData;
public LiveData<List<LocationModel>> getAllLocationsLiveData() {
return allLocationsLiveData;
}
public LocationsViewModel(#NonNull Application application) {
super(application);
locationRepository = new LocationRepository(application);
allLocationsLiveData = locationRepository.getAllLocation();
}
}
Repository:
public class LocationRepository {
private final LocationDao locationDao;
private LiveData<List<LocationModel>> allLocation;
LiveData<List<LocationModel>> getAllLocation() {
return allLocation;
}
LocationRepository(Application application){
LocationsDatabase db = LocationsDatabase.getDatabase(application);
locationDao = db.locationDao();
allLocation = locationDao.getAllLocations();
}
}
init method from Fragment:
private void initData() {
locationsViewModel = ViewModelProviders.of(this).get(LocationsViewModel.class);
locationsViewModel.getAllLocationsLiveData().observe(this, new Observer<List<LocationModel>>() {
#Override
public void onChanged(#Nullable List<LocationModel> locations) {
mAdapter.setLocationList(locations);
}
});
}
Dao:
#Dao
public interface LocationDao {
#Insert(onConflict = OnConflictStrategy.IGNORE)
void insert(LocationModel... locations);
#Query("SELECT * FROM LocationModel")
LiveData<List<LocationModel>> getAllLocations();
}
So why I'm able to getFromDatabse from UI, but need other thread for save ?
You use LiveData, which literally runs on a background thread.
It does not happen synchronously, so it does not happen on the main thread.
You subscribe for changes, and those changes are calculated on a background thread, and then only given to your Activity/Fragment on the main thread.
When you try to save something, you don't use LiveData (which you aren't supposed to either, so its all good), so it runs on the main thread. Which it shouldn't.
So you'll need to run it in a new thread, create an AsyncTask, or similar.
I am working on the design of a multi-threading app in Javafx and would like to have a TableView with columns for Name and Progress of each Thread. After doing much research I found a similar example of what I am trying to accomplish here:
JavaFX Update progressbar in tableview from Task
(Which points to this: 'https://community.oracle.com/message/10999916')
The problem I am running into, however, is illustrated well in this example; how can you call a 'Task' object multiple times to update a ProgressIndicator?
My understanding from Oracle's documentation is that a Task object "is a one-shot class and cannot be reused". It would seem then that one can only invoke the call() method of a Task object once. I need to update the Task multiple times as it progresses through a Thread class, not call it once and arbitrarily increment through a For loop.
I have read about binding to Listeners and creating Service classes, but I am unsure if those are actual resolutions to this problem. I would therefore like to ask if this is even possible in Javafx, or if perhaps I am overlooking something. In the event someone has accomplished this in the past, it would be tremendously helpful if you might be able to illustrate how through the example provided previously.
Any direction on this would be appreciated, thank you.
-Drew
EDIT 1: I edited my wording as it was inaccurate.
EDIT 2: Here is an example with some pseudo code. Say I had a class with the following code:
public static class TaskEx extends Task<Void>{
#Override
protected Void call(){
updateProgress(.5, 1);
return null
}
public static void callThread() {
TableView<TaskEx> table = new TableView<TaskEx>();
//Some code for data in table.
TableColumn progressColumn = new TableColumn ("Progress");
progressColumn.setCellValueFactory(new PropertyValueFactor("progress");
table.setItems(<data>);
table.getColumns();addAll(progressColumn);
ExecutorService executor = Executors.newFixedThreadPool(<SomeNumber>);
for(TaskEx task : table.getItems(){
Threading.ThreadClass newThread = new Threading.ThreadClass(task);
executor.submit(newThread, <uniqueID>);
}
}
Then say I had a second class for Threading with this logic:
static class ThreadClass extends Thread{
Task progressTask;
public ThreadClass(Task task, Integer id){
progressTask = task;
}
public void run(){
ExecutorService executor = Executors.newFixedThreadPool(<someNumber>);
//This invokes the Task call for the correct progressIndicator in the Tableview.
//It will correctly set the progressIndicator to 50% done.
executor.submit(progressTask);
/* Main logic of the Threading class that involves the 'id' passed in. */
//This will do nothing because you cannot invoke the Task call more than once.
executor.submit(progressTask);
}
}
That is the sort of workflow I need, but I'm unsure how to accomplish this.
It seems like you don't get what we were talking about. You are trying to do your logic in the Thread.run(), and then each thread is creating a Task just to do the update of progress.
What you need is really to shift your logic from Thread.run() to Task.call(). Your thread is really just a thread, and all it does is to run a Runnable object (which is the Task).
public class TaskEx extends Task<Void> {
#Override
protected Void call() {
// Do whatever you need this thread to do
updateProgress(0.5, 1);
// Do the rest
updateProgress(1, 1);
}
}
public static void callThread() {
TableView<TaskEx> table = new TableView<TaskEx>();
ObservableList<TaskEx> data = FXCollections.observableArrayList<>();
data.add(new TaskEx()); // Add the data you need
TableColumn progressColumn = new TableColumn("Progress");
progressColumn.setCellValueFactory(new PropertyValueFactory("progress"));
progressColumn.setCellFactory(column -> {
return new TableCell<TaskEx, Double> {
private final ProgressBar bp = new ProgressBar();
#Override
public void updateItem(Double item, boolean empty) {
super.updateItem(item, empty);
if (empty || item == null) {
setText(null);
setGraphic(null);
}
else {
bp.setProgress(item.doubleValue());
setGraphic(bp);
}
}
}
});
table.setItems(data);
table.getColumns().add(progressColumn);
ExecutorService executor = Executors.newFixedThreadPool(data.size());
for (TaskEx task : table.getItems()) {
executor.submit(task);
}
}
This implement removes ThreadClass because there should not be any logic that must be done at a thread sub-class. If you really need to access the thread object as part of your logic, call Thread.getCurrentThread() from your TaskEx.call().
This implement also opens multiple threads doing exactly the same thing (which is quite meaningless). If you need to do a set of different logics, you can either make a set of different Task subclasses, or add a constructor taking in Runnable objects in TaskEx.
E.g.
public class TaskEx extends Task<Void> {
private final Runnable[] logics;
public TaskEx(Runnable[] logics) {
this.logics = logics;
}
#Override
protected Void call() {
for (int i = 0; i < logics.length; i++) {
logics[i].run();
updateProgress(i, logics.length);
}
}
}
I'm using Guava Eventbus in Vaadin+Spring project and started to have a problem with posting an event from background thread.
Eventbus is instantiated in wrapper class. Objects communicate with the eventbus using static method defined in main UI class to obtain the eventbus object. It is the same way as proposed in Vaadin Dashboard example (DashboardEventBus).
public class MainUI extends UI implements ViewDisplay
{
private EventBusWrapper eventbus_ = new EventBusWrapper();
public static EventBusWrapper GetEventBusWrapper()
{
return ((MainUI) getCurrent()).eventbus_;
}
}
Problem appears in presenter/services classes where I create new thread class and start the thread.
Inside Runnable implemenation of run method I create another object which makes some job.
public class SearchResultsPresenter extends AbstractPresenter<SearchResultView>
{
public SearchResultsPresenter()
{
EventBusWrapper.register(this);
}
#Subscribe
public void UserSearchRequested(Event.UserSearchRequestEvent e)
{
new UpdateContentComponentThread(e.GetSearchElem()).start();
}
#Subscribe
public void UserSearchAppendFoundElement(Event.UserSearchElementFound e)
{
if(e.GetElement().IsValid())
view_.AddElement(e.GetElement());
}
public class UpdateContentComponentThread extends Thread
{
private final Search searcher_;
UpdateContentComponentThread(SearchElement search)
{
searcher_ = new DefaultSearch(search);
}
#Override
public void run()
{
searcher_.Search();
}
}
}
It performs some validation/checking and creates other helper classes.
public class DefaultSearch implements Search
{
private final Scraper scraper_;
...
#Override
public void Search()
{
if(!scraper_.IsConfigured())
return;
...
scraper_.FindElements();
}
}
Then inside scraper's FindElements body I try to post an event using static post method defined in EventBusWrapper.
public class HttpElementScraper extends WebScraper
{
...
#Override
public Collection<Element> FindElements()
{
...
Element elem = ...
Event.UserSearchElementFound e = new Event.UserSearchElementFound(elem);
EventBusWrapper.post(e);
return foundelements;
}
}
At this moment the NullPointerException is thrown and I cannot solve and help myself with the problem.
Exception in thread "Thread-10" java.lang.NullPointerException
at com.project.MainUI.GetEventBusWrapper(MainUI.java:109)
at com.project.events.EventBusWrapper.register(EventBusWrapper.java:24)
at com.project.service.search.scraper.HttpElementScraper.FindElements(HttpElementScraper.java:92)
at com.project.service.search.DefaultSearch.Search(DefaultSearch.java:38)
at com.project.view.search.SearchResultsPresenter$UpdateContentComponentThread.run(SearchResultsPresenter.java:71)
// I ommited not important lines of code and annotations. Most of the components and services connected with them are UIscoped.
Vaadin assumes that access to Vaadin component (and related) instances is synchronized properly. When using the traditional single-threaded request-response cycle to access components it's synchronized automatically.
When using external threads, you need to synchronize code accessing your Vaadin components by using UI.access(). For example:
getUI().access(() -> label.setValue("Hello"));
In my application I have the following potentially long running classes:
ScheduleLocalNotificationsOperation
UnScheduleLocalNotificationsOperation
SyncEventsToDeviceCalendarOperation
UnSyncEventsToDeviceCalendarOperation
SaveProductsToLocalStorageImpl
and so on.
Most of these are structured this way:
public interface Operation {
void execute();
}
public class ScheduleLocalNotificationsOperation implements Operation {
private MyApplication application;
private List<LocalNotificationDescriptor> localNotifications;
public ScheduleLocalNotificationsOperation (MyApplication application, List<LocalNotificationDescriptor> localNotifications) {
this.application = application;
this.localNotifications = localNotifications;
}
#Override
public void execute() {
// Do some stuff
}
}
Ideally, I would like to design my Operation classes to be concurrency agnostic, and to be able to impose some multithreading policy on them from the outside, like so:
public class MainActivity extends Activity {
public static ExecutorService executorService = Executors.newCachedThreadPool();
#Override
public void onCreate() {
executorService.submit(new Runnable {
#Override
public void run() {
new ScheduleLocalNotificationsOperation(application, createLocalNotificationsList()).execute();
}
});
}
}
But this way I should implement some concurrency policy in every client, every time I call those classes.
On the other hand, I dont want to interrupt the pure logic in those operations by adding concurrency to them, so my question is basically, from design stand point what is the better way to do this, if there is a clearly defined one?
Can I create an OperationsRunner class that will be called by any client and will execute any Operation using polymorphism and make that class be the only one that deals with concurrency?