JavaFX extends Service<> return value - javafx

I have task in my app, and i do not know how it works return from this task.
public class TimeManager extends Service<String> {
#Override
protected Task<String> createTask() {
return new Task<String>() {
#Override
protected String call() throws Exception {
String txt = null;
while (!isCancelled()) {
try {
txt = "some txt";
Thread.sleep(1000);
} catch (InterruptedException e) {
System.out.println(e.getMessage());
}
}
return txt;
}
};
}
And in Main Class:
TimeManager time = new TimeManager();
time.start();
time.getValue();
time allways return null. What do I have to do to return the value?
Thread works good and I can send data from the thread to the application

Your task does not publish intermediate updates. Furthermore Service is used to run tasks in background threads to avoid blocking the JavaFX application thread. For this reason the value is likely to not be assigned if you access it directly after starting the service. It would be better to use a binding or a listener to the value property to retrieve the data when it's assigned.
public class TimeManager extends Service<String> {
#Override
protected Task<String> createTask() {
return new Task<String>() {
int i = 0;
#Override
protected String call() throws Exception {
String txt = null;
while (!isCancelled()) {
txt = Integer.toString(++i);
updateValue(txt); // publish new value
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
System.out.println(e.getMessage());
}
}
return txt;
}
};
}
}
TimeManager time = new TimeManager();
label.textProperty().bind(time.valueProperty());
time.start();
Note that in this case a service may not be required since you're running only a single task. Running the Task instance using new Thread(task).start() may actually suffice.
Furthermore there are better options for scheduling fast repeating updates of the GUI, see JavaFX periodic background task

Related

How to use ContainerStoppingErrorHandler in #KafkaListener to terminate application incase of Kafka server DisconnectException

I want to handle the Server DisconnectException and terminate the application when the server DisconnectException occurs
how to catch this error and stop the application?
#KafkaListener(topics = { "${kafka.status-topic}", "${kafka.start-topic}" }, containerFactory = "kafkaListenerContainerFactory")
public void listen(#Payload final String message,
#Header(KafkaHeaders.RECEIVED_TOPIC) final String topic) {
log.debug("Received '{}'-message {} from Kafka", topic, message);
LinkedList<IMessageListener> topicListeners = listeners.get(topic);
for (final IMessageListener l : topicListeners) {
// call listeners in a separate thread
executor.execute(new Runnable() {
#Override
public void run() {
l.messageReceived(topic, message);
}
});
}
}
You can try catching the exception and then calling System.exit(0) inside catch block

JavaFX many task work in GUI

I ran a thread that updates the open time of the application. It works well. I've expanded the Service class. The time from this task update my GUI, textField by Platform.runLater
#Override
protected Task<Void> createTask() {
return new Task<Void>() {
#Override
protected Void call() throws Exception {
while (!isCancelled()) {
if (isPause == false) {
try {
Platform.runLater(() -> {
currentTimeInApp = currentTimeInApp + 1;
upPanelController.timeInApp.setText
(currentTimeInApp.toString());
}
});
Thread.sleep(1000);
} catch (InterruptedException e) {
System.out.println(e.getMessage());
}
if (isCancelled())
break;
}
}
return null;
}
};
}
I would like to run a second thread which also updates GUI. I can't run the same thread. Can two independent threads be updated GUI ?
Most of the information on the internet is dedicated to one topic. Thank you for every suggestion
Yes, you can use as many threads as you like. You just have to make sure that you always do the GUI update via Platform.runLater.

JavaFX - Call "updateMessage" for TextArea from background Task - Two problems found

I am having two problems when trying to use "updateMessage" in a JavaFX task.
Issue #1
seems to be a known behavior, but I am not yet sure how exactly I can workaround it.This one is not (yet) critical to me.
The problem is that not all the updates I am performing in a background Task are displayed in the UI (at least the UI does not hang/freezes anymore, which was my initial issue).
My Code of the UI part:
TextArea console = new TextArea();
Button button01 = new Button("Start");
button01.setOnAction(new EventHandler() {
#Override
public void handle(Event event) {
if (ms.getState() == State.READY) {
ms.messageProperty().addListener(new ChangeListener<String>() {
#Override
public void changed(ObservableValue<? extends String> observable,
String oldValue, String newValue) {
console.appendText(newValue+"\n");
}
});
ms.start();
}
}
});
My Service:
public class MyService extends Service<Object> {
#Override
protected Task createTask() {
//here we use "MyTask" first to show problem #1
MyTask ct = new MyTask();
//here we use "MyTask2" first to show problem #2
// MyTask2 ct = new MyTask2();
try {
ct.call();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("MyService end");
return ct;
}
}
My Task (#1)
public class MyTask extends Task<Object> {
#Override
public EventHandler<WorkerStateEvent> call() {
System.out.println("call() is called");
if (Thread.currentThread().getName().equals("JavaFX Application Thread")){//yes, this might not be right, but if I do not do this, my stuff is executed twice because "call()" is called twice, but the textarea area is just updated in the second run (the non javafx application thread).
return null;
} else{
//actually here I want to do some 'heavy' stuff in the background
//and many things of this heavy stuff should be displayed / logged within the UI
//but very likely (hopefully) new messages (updateMessage) will not be send as fast as in the following loop
for (int i=0;i<10000000;i++){
updateMessage("This is update number'"+i+"' from the background thread");
}
Platform.runLater(new Runnable() {
#Override
public void run() {
try{
//here is the chance to get back to the view
}finally{
}
}
});
return null;
}
}
This basically works, but not every single loop is displayed in the UI.
How do I (correctly) make sure every loop is displayed?
Screenshot: Messages are displayed but not for every loop
Issue #2
Currently blocks my attempt to bring my little text-based game into a JavaFX application.
The main problem is that I am able to call "updateMessage" from the Task directly (see above), but not from a another (sub-)class which I would need to bring all message updates from my game (each message describes the progress of the game) to the UI.
The Task I use (Task #2):
public class MyTask2 extends Task<Object> {
#Override
public EventHandler<WorkerStateEvent> call() {
// ...
UITools myTools = new UITools();
myTools.logToUITest("Just one simple message");
// ...
Platform.runLater(new Runnable() {
#Override
public void run() {
try{
//here is the chance to get back to the view
}finally{
}
}
});
return null;
}
and the (sub-)class that I want to use to do the updateMessage (actually in my little game there would be even more classes that are called during the game and almost all of them trigger an update/message).
public class UITools {
public void logToUITest(String message){
updateMessage(message);
//how to allow 'updateMessage' from the Task to be executed from here?
}
This already results in "The method updateMessage(String) is undefined...".
How could I make it possible to call the updateMessage outside of the Task itself?
updateMessage() can only be called from within the call() method of a Task. It's a constraint imposed by the design of the Task class.
The missed message updates are due to the fact that there are too many updates and not all of them are forwarded to the event queue. Try to reduce the number of updates or sleep for a little while to separate them out in time

How to disable Redis Caching at run time if redis connection failed

We have rest api application. We use redis for API response caching and internal method caching. If redis connection then it is making our API down. We want to bypass the redis caching if that redis connection fails or any exception instead of making our API down.
There is a interface CacheErrorHandler but it handles the redis get set operation failures not redis connection problems. We are using Spring 4.1.2.
Let's boil this down a bit. Your application uses caching (implemented with Redis). If the Redis connection is stale/closed or otherwise, then you want the application to bypass caching and (presumably) go directly to an underlying data store (e.g. RDBMS). The application Service logic might look similar to...
#Service
class CustomerService ... {
#Autowired
private CustomerRepository customerRepo;
protected CustomerRepository getCustomerRepo() {
Assert.notNull(customerRepo, "The CustomerRepository was not initialized!");
return customerRepo;
}
#Cacheable(value = "Customers")
public Customer getCustomer(Long customerId) {
return getCustomerRepo().load(customerId);
}
...
}
All that matters in Spring core's Caching Abstraction to ascertain a Cache "miss" is that the value returned is null. As such, Spring Caching Infrastructure will then proceed in calling the actual Service method (i.e. getCustomer). Keep in mind on the return of the getCustomerRepo().load(customerId) call, you also need to handle the case where Spring's Caching Infrastructure attempts to now cache the value.
In the spirit of keeping it simple, we will do without AOP, but you should be able to achieve this using AOP as well (your choice).
All you (should) need is a "custom" RedisCacheManager extending the SDR CacheManager implementation, something like...
package example;
import org.springframework.cache.Cache;
import org.springframework.data.redis.cache.RedisCacheManager;
...
class MyCustomRedisCacheManager extends RedisCacheManager {
public MyCustomerRedisCacheManager(RedisTemplate redisTemplate) {
super(redisTemplate);
}
#Override
public Cache getCache(String name) {
return new RedisCacheWrapper(super.getCache(name));
}
protected static class RedisCacheWrapper implements Cache {
private final Cache delegate;
public RedisCacheWrapper(Cache redisCache) {
Assert.notNull(redisCache, "'delegate' must not be null");
this.delegate = redisCache;
}
#Override
public Cache.ValueWrapper get(Object key) {
try {
delegate.get(key);
}
catch (Exception e) {
return handleErrors(e);
}
}
#Override
public void put(Object key, Object value) {
try {
delegate.put(key, value);
}
catch (Exception e) {
handleErrors(e);
}
}
// implement clear(), evict(key), get(key, type), getName(), getNativeCache(), putIfAbsent(key, value) accordingly (delegating to the delegate).
protected <T> T handleErrors(Exception e) throws Exception {
if (e instanceof <some RedisConnection Exception type>) {
// log the connection problem
return null;
}
else if (<something different>) { // act appropriately }
...
else {
throw e;
}
}
}
}
So, if Redis is unavailable, perhaps the best you can do is log the problem and proceed to let the Service invocation happen. Clearly, this will hamper performance but at least it will raise awareness that a problem exists. Clearly, this could be tied into a more robust notification system, but it is a crude example of the possibilities. The important thing is, your Service remains available while the other services (e.g. Redis) that the application service depends on, may have failed.
In this implementation (vs. my previous explanation) I chose to delegate to the underlying, actual RedisCache implementation to let the Exception occur, then knowing full well a problem with Redis exists, and so that you can deal with the Exception appropriately. However, if you are a certain that the Exception is related to a connection problem upon inspection, you can return "null" to let Spring Caching Infrastructure proceed as if it were a Cache "miss" (i.e. bad Redis Connection == Cache miss, in this case).
I know something like this should help your problem as I built a similar prototype of a "custom" CacheManager implementation for GemFire and one of Pivotal's customers. In that particular UC, the Cache "miss" had to be triggered by an "out-of-date version" of the application domain object where production had a mix of newer and older application clients connecting to GemFire through Spring's Caching Abstraction. The application domain object fields would change in newer versions of the app for instance.
Anyway, hope this helps or gives you more ideas.
Cheers!
So, I was digging through the core Spring Framework Caching Abstraction source today addressing another question and it seems if a CacheErrorHandler is implemented properly, then perhaps a problematic Redis Connection could still result in the desired behavior, e.g. cache "miss" (triggered with the return of a null value).
See the AbstractCacheInvoker source for more details.
The cache.get(key) should result in an exception due to a faulty Redis Connection and thus Exception handler would be invoked...
catch (RuntimeException e) {
getErrorHandler().handleCacheGetError(e, cache, key);
return null; // If the exception is handled, return a cache miss
}
If the CacheErrorHandler properly handles the Cache "get" error (and does not re-throw the/an Exception), then a null value will be returned indicating a cache "miss".
Thank you #John Blum. My solution in Spring Boot is as follows.
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cache.Cache;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.util.Assert;
import java.util.concurrent.Callable;
class CustomRedisCacheManager extends RedisCacheManager {
private static Logger logger = LoggerFactory.getLogger(CustomRedisCacheManager.class);
public CustomRedisCacheManager(RedisOperations redisOperations) {
super(redisOperations);
}
#Override
public Cache getCache(String name) {
return new RedisCacheWrapper(super.getCache(name));
}
protected static class RedisCacheWrapper implements Cache {
private final Cache delegate;
public RedisCacheWrapper(Cache redisCache) {
Assert.notNull(redisCache, "delegate cache must not be null");
this.delegate = redisCache;
}
#Override
public String getName() {
try {
return delegate.getName();
} catch (Exception e) {
return handleException(e);
}
}
#Override
public Object getNativeCache() {
try {
return delegate.getNativeCache();
} catch (Exception e) {
return handleException(e);
}
}
#Override
public Cache.ValueWrapper get(Object key) {
try {
return delegate.get(key);
} catch (Exception e) {
return handleException(e);
}
}
#Override
public <T> T get(Object o, Class<T> aClass) {
try {
return delegate.get(o, aClass);
} catch (Exception e) {
return handleException(e);
}
}
#Override
public <T> T get(Object o, Callable<T> callable) {
try {
return delegate.get(o, callable);
} catch (Exception e) {
return handleException(e);
}
}
#Override
public void put(Object key, Object value) {
try {
delegate.put(key, value);
} catch (Exception e) {
handleException(e);
}
}
#Override
public ValueWrapper putIfAbsent(Object o, Object o1) {
try {
return delegate.putIfAbsent(o, o1);
} catch (Exception e) {
return handleException(e);
}
}
#Override
public void evict(Object o) {
try {
delegate.evict(o);
} catch (Exception e) {
handleException(e);
}
}
#Override
public void clear() {
try {
delegate.clear();
} catch (Exception e) {
handleException(e);
}
}
private <T> T handleException(Exception e) {
logger.error("handleException", e);
return null;
}
}
}
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.core.RedisTemplate;
#Configuration
public class RedisConfig {
#Bean
public RedisCacheManager redisCacheManager(RedisTemplate redisTemplate) {
CustomRedisCacheManager redisCacheManager = new CustomRedisCacheManager(redisTemplate);
redisCacheManager.setUsePrefix(true);
return redisCacheManager;
}
}
actually my response is directed to Mr. #Vivek Aditya - I faced the same problem: new spring-data-redis api and not constructing RedisCacheManager per RedisTemplate. The only option - based on #John Blum suggestions - was to use aspects. And below is my code.
#Aspect
#Component
public class FailoverRedisCacheAspect {
private static class FailoverRedisCache extends RedisCache {
protected FailoverRedisCache(RedisCache redisCache) {
super(redisCache.getName(), redisCache.getNativeCache(), redisCache.getCacheConfiguration());
}
#Override
public <T> T get(Object key, Callable<T> valueLoader) {
try {
return super.get(key, valueLoader);
} catch (RuntimeException ex) {
return valueFromLoader(key, valueLoader);
}
}
private <T> T valueFromLoader(Object key, Callable<T> valueLoader) {
try {
return valueLoader.call();
} catch (Exception e) {
throw new ValueRetrievalException(key, valueLoader, e);
}
}
}
#Around("execution(* org.springframework.cache.support.AbstractCacheManager.getCache (..))")
public Cache beforeSampleCreation(ProceedingJoinPoint proceedingJoinPoint) {
try {
Cache cache = (Cache) proceedingJoinPoint.proceed(proceedingJoinPoint.getArgs());
if (cache instanceof RedisCache) {
return new FailoverRedisCache((RedisCache) cache);
} else {
return cache;
}
} catch (Throwable ex) {
return null;
}
}
}
works fine for all reasonable scenarios:
app starts fine with redis down
app (still) works during (sudden) redis outage
when redis starts working again, app sees it
Edit: the code is more like a poc - only for "get", and I don't like reinstantiating FailoverRedisCache every single cache hit - there should be a map.
None of the above worked for us when using Spring Boot 2.3.9.release with Redis. We ended up creating and registering our own customized CacheErrorHandler named CustomCacheErrorHandler to override the default SimpleCacheErrorHandler provided by Spring Framework. This will work perfectly.
#Configuration
public class CachingConfiguration extends CachingConfigurerSupport {
#Override
public CacheErrorHandler errorHandler() {
return new CustomCacheErrorHandler();
}
}
class CustomCacheErrorHandler implements CacheErrorHandler {
Logger log = Logger.get(CustomCacheErrorHandler.class);
#Override
public void handleCacheGetError(RuntimeException e, Cache cache, Object o) {
log.error(e.getMessage(), e);
}
#Override
public void handleCachePutError(RuntimeException e, Cache cache, Object o, Object o1) {
log.error(e.getMessage(), e);
}
#Override
public void handleCacheEvictError(RuntimeException e, Cache cache, Object o) {
log.error(e.getMessage(), e);
}
#Override
public void handleCacheClearError(RuntimeException e, Cache cache) {
log.error(e.getMessage(), e);
}
}
I had same problem, but, unfortunately, none of the above solutions work for me. I checked for the problem and found out that the executed command never timed out if there was no connection to Redis. So I start to study lettuce library for a solution. I solve the problem by rejecting the command when there is no connection:
#Bean
public LettuceConnectionFactory lettuceConnectionFactory()
{
final SocketOptions socketOptions = SocketOptions.builder().connectTimeout(Duration.ofSeconds(10)).build();
ClientOptions clientOptions = ClientOptions.builder()
.socketOptions(socketOptions)
.autoReconnect(true)
.disconnectedBehavior(ClientOptions.DisconnectedBehavior.REJECT_COMMANDS)
.build();
LettuceClientConfiguration clientConfig = LettuceClientConfiguration.builder()
.commandTimeout(Duration.ofSeconds(10))
.clientOptions(clientOptions).build();
RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration(this.host, this.port);
return new LettuceConnectionFactory(redisStandaloneConfiguration, clientConfig);
}
All the core Spring Framework Cache abstraction annotations (e.g. #Cacheable) along with the JSR-107 JCache annotations supported by the core SF delegate to the underlying CacheManager under-the-hood, and for Redis, that is the RedisCacheManager.
You would configure the RedisCacheManager in Spring XML configuration meta-data similar to here.
One approach would be to write an AOP Proxy for the (Redis)CacheManager that uses the RedisConnection (indirectly from the RedisTemplate) to ascertain the state of the connection on each (Redis)CacheManger operation.
If the connection has failed, or is closed, for standard cache ops, the (Redis)CacheManager could return an instance of RedisCache for getCache(String name) that always returns null (indicating a Cache miss on an entry), thus passing through to the underlying data store.
There maybe better ways to handle this as I am not an expert on all things Redis (or SDR), but this should work and perhaps give you a few ides of your own.
Cheers.
You can use CacheErrorHandler. But you should make sure to make
RedisCacheManager transactionAware to false in your Redis Cache Config(to make sure the transaction is committed early when executing the caching part and the error is caught by CacheErrorHandler and don't wait until the end of the execution which skips CacheErrorHandler part). The function to set transactionAware to false looks like this:
#Bean
public RedisCacheManager redisCacheManager(LettuceConnectionFactory lettuceConnectionFactory) {
JdkSerializationRedisSerializer redisSerializer = new JdkSerializationRedisSerializer(getClass().getClassLoader());
RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofHours(redisDataTTL))
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer));
redisCacheConfiguration.usePrefix();
RedisCacheManager redisCacheManager = RedisCacheManager.RedisCacheManagerBuilder.fromConnectionFactory(lettuceConnectionFactory)
.cacheDefaults(redisCacheConfiguration)
.build();
redisCacheManager.setTransactionAware(false);
return redisCacheManager;
}

Windows service starts and exits immediately

I have written a windows service which in turn calls a web service. When I run the windows service from a test app., it works perfectly. However when I install the service and then start it, it stops almost immediately. The only two entries I see in the log are Constructor and Thread Started. Not sure what is wrong.
public partial class WindowsService : ServiceBase
{
public LogManager.LogFile _log;
public Thread m_thread;
protected TimeSpan m_delay;
CommonFunctions _cf = new CommonFunctions();
DBFunctions _db = new DBFunctions();
public WindowsService()
{
InitializeComponent();
_log = new LogManager.LogFile(#"c:\test\servicelog.txt", true, true);
_log.WriteToLog("Constructor", LogLevel.Level0);
}
protected override void OnStart(string[] args)
{
m_delay = new TimeSpan(0,0,300);
base.OnStart(args);
try
{
m_thread = new System.Threading.Thread(Execute);
m_thread.Start();
_log.WriteToLog("Thread Started", LogLevel.Level0);
}
catch (Exception ex)
{ _log.WriteToLog(ex.Message, LogLevel.Level0); }
}
public void Execute()
{
_log.WriteToLog("Begin Execute...", LogLevel.Level0);
try
{
ProcessNewLMSUsers();
}
catch (Exception ex)
{
_log.WriteToLog(ex.Message.ToString());
}
}
private void ProcessNewLMSUsers()
{
try
{
_log.WriteToLog("Begin: Processing new LMS Users", LogLevel.Level1);
// Check for new users in the LMS.
string callErrorText = "";
bool userAdded = false;
LMSWS.SSO lms = _cf.GetLMSSSOWS(); **// this is a web service**
lms.Timeout = 99999;
}
REST OF THE CODE.................
}
I can't see there is anything wrong with your code. but you can try to put a "Thread.Sleep(20000); " code at the begining of OnStart method. e.g.
protected override void OnStart(string[] args)
{
Thread.Sleep(20000);
m_delay = new TimeSpan(0,0,300); //set a break-point here
base.OnStart(args);
try
{
m_thread = new System.Threading.Thread(Execute);
m_thread.Start();
_log.WriteToLog("Thread Started", LogLevel.Level0);
}
catch (Exception ex)
{ _log.WriteToLog(ex.Message, LogLevel.Level0); }
}
and once you start this service program in Windows Service, then you have to quickly attach you source code to the service program. In visual studio, it's menu "Debug" -> "Attach to Process...". then you can set break-point in your source code anywhere to check what's going wrong.

Resources