DeferredResult with time consuming processing resulting in exception - spring

I have one class that extends DeferredResults and extends Runnable as shown below
public class EventDeferredObject<T> extends DeferredResult<Boolean> implements Runnable {
private Long customerId;
private String email;
#Override
public void run() {
RestTemplate restTemplate=new RestTemplate();
EmailMessageDTO emailMessageDTO=new EmailMessageDTO("dineshshe#gmail.com", "Hi There");
//Very long running call
Boolean result=restTemplate.postForObject("http://localhost:9080/asycn/sendEmail", emailMessageDTO, Boolean.class);
this.setResult(result);
}
//Constructor and getter and setters
}
Now I have controller that return the object of the above class,whenever new request comes to controller we check if that request is present in HashMap(That stores unprocessed request at that instance).If not present then we are creating object of EventDeferredObject class can store that in HashMap and call start() method on it.If this type request is already present then we will return that from HashMap.On completion on request we will delete that request from HashMap.
#RequestMapping(value="/sendVerificationDetails")
public class SendVerificationDetailsController {
private ConcurrentMap<String , EventDeferredObject<Boolean>> requestMap=new ConcurrentHashMap<String , EventDeferredObject<Boolean>>();
#RequestMapping(value="/sendEmail",method=RequestMethod.POST)
public EventDeferredObject<Boolean> sendEmail(#RequestBody EmailDTO emailDTO)
{
EventDeferredObject<Boolean> eventDeferredObject = null;
System.out.println("Size:"+requestMap.size());
if(!requestMap.containsKey(emailDTO.getEmail()))
{
eventDeferredObject=new EventDeferredObject<Boolean>(emailDTO.getCustomerId(), emailDTO.getEmail());
requestMap.put(emailDTO.getEmail(), eventDeferredObject);
Thread t1=new Thread(eventDeferredObject);
t1.start();
}
else
{
eventDeferredObject=requestMap.get(emailDTO.getEmail());
}
eventDeferredObject.onCompletion(new Runnable() {
#Override
public void run() {
if(requestMap.containsKey(emailDTO.getEmail()))
{
requestMap.remove(emailDTO.getEmail());
}
}
});
return eventDeferredObject;
}
}
Now as the processing of call in threads run() method takes 50000ms time so this results in exception as:
java.lang.IllegalStateException: Cannot forward after response has been committed
at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:328)
at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:318)
at org.apache.catalina.core.StandardHostValve.custom(StandardHostValve.java:433)
at org.apache.catalina.core.StandardHostValve.status(StandardHostValve.java:299)
at org.apache.catalina.core.StandardHostValve.throwable(StandardHostValve.java:393)
at org.apache.catalina.core.AsyncContextImpl.setErrorState(AsyncContextImpl.java:434)
at org.apache.catalina.connector.CoyoteAdapter.asyncDispatch(CoyoteAdapter.java:310)
at org.apache.coyote.http11.AbstractHttp11Processor.asyncDispatch(AbstractHttp11Processor.java:1682)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:649)
at org.apache.coyote.http11.Http11NioProtocol$Http11ConnectionHandler.process(Http11NioProtocol.java:222)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1556)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1513)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)
How to tackle this situation..if the processing time is around 20000ms code works fine.

Related

Register DynamicParameterizedType global

How can i register a global available DynamicParameterizedType in hibernate?
I wrote the following type:
public class QuantityType extends AbstractSingleColumnStandardBasicType<Quantity<?>> implements DynamicParameterizedType {
public static final QuantityType INSTANCE = new QuantityType();
public QuantityType() {
super(DoubleTypeDescriptor.INSTANCE, new QuantityJavaDescriptor(AbstractUnit.ONE));
}
#Override
public String getName() {
return QuantityType.class.getSimpleName();
}
#Override
public void setParameterValues(Properties parameters) {
ParameterType reader = (ParameterType) parameters.get(PARAMETER_TYPE);
if (reader == null) throw new RuntimeException("Not Implemented");
Unit<?> resolvedUnit = resolveUnit(reader);
setJavaTypeDescriptor(new QuantityJavaDescriptor(resolvedUnit));
}
private Unit<?> resolveUnit(ParameterType reader) {...}
}
and registered it with a service registration in hibernate:
public class QuantityTypeRegistration implements TypeContributor {
#Override
public void contribute(TypeContributions typeContributions, ServiceRegistry serviceRegistry) {
typeContributions.contributeType(QuantityType.INSTANCE);
}
}
If i use the type in an entity, the wrap/unwrap method of the JavaTypeDescriptor gets called,
but instead of the parameterized JavaTypeDescriptor, the default JavaTypeDescriptor gets called. For some reason the setParameterValues method was not called.
Code: https://github.com/raynigon/unit-api/tree/master/jpa-starter/src/main/java/com/raynigon/unit_api/jpa

How to get a Room Database ViewModel instance inside WorkManager?

I am newbie in Android development. I am failing to get the room db viewmodel which extends AndroidViewModel inside WorkManager. I want to get a viewmodel class instance to do insert inside room db.
AppAdViewModel.class
public class AppAdViewModel extends AndroidViewModel {
private AppAdRepository appAdRepository;
public AppAdViewModel(#NonNull Application application) {
super(application);
appAdRepository = new AppAdRepository(application);
}
public void insert(AppAdModel appAdModel){
appAdRepository.insertAd(appAdModel);
}
}
MyBackgroundWorker.class
public class AppDataSyncingworker extends Worker{
private Context context;
private AppAdViewModel appAdViewModel;
public AppDataSyncingworker(#NonNull Context context, #NonNull WorkerParameters workerParams){
super(context, workerParams);
}
#NonNull
#Override
public Result doWork() {
this.context = getApplicationContext();
// error on this line
this.appAdViewModel = new ViewModelProvider((AppCompatActivity)context).get(AppAdViewModel.class);
return null;
}
The error it's showing is:
java.util.concurrent.ExecutionException: java.lang.ClassCastException: android.app.Application cannot be cast to androidx.appcompat.app.AppCompatActivity
at androidx.work.impl.utils.futures.AbstractFuture.getDoneValue(AbstractFuture.java:516)
at androidx.work.impl.utils.futures.AbstractFuture.get(AbstractFuture.java:475)
at androidx.work.impl.WorkerWrapper$2.run(WorkerWrapper.java:298)
at androidx.work.impl.utils.SerialExecutor$Task.run(SerialExecutor.java:91)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:764)
Caused by: java.lang.ClassCastException: android.app.Application cannot be cast to androidx.appcompat.app.AppCompatActivity
Any help or guide what i am doing wrong?
Calling getApplicationContext() should not be the preferred way of getting the Context. public constructor of Worker takes a Context as the first parameter. You can use that

JSON-B serializes Map keys using toString and not with registered Adapter

I have a JAX-RS service that returns a Map<Artifact, String> and I have registered a
public class ArtifactAdapter implements JsonbAdapter<Artifact, String>
which a see hit when deserializing the in-parameter but not when serializing the return value, instead the Artifact toString() is used. If I change the return type to a Artifact, the adapter is called. I was under the impression that the Map would be serialized with built-in ways and then the adapter would be called for the Artifact.
What would be the workaround? Register an Adapter for the whole Map?
I dumped the thread stack in my toString and it confirms my suspicions
at java.lang.Thread.dumpStack(Thread.java:1336)
Artifact.toString(Artifact.java:154)
at java.lang.String.valueOf(String.java:2994)
at org.eclipse.yasson.internal.serializer.MapSerializer.serializeInternal(MapSerializer.java:41)
at org.eclipse.yasson.internal.serializer.MapSerializer.serializeInternal(MapSerializer.java:30)
at org.eclipse.yasson.internal.serializer.AbstractContainerSerializer.serialize(AbstractContainerSerializer.java:63)
at org.eclipse.yasson.internal.Marshaller.serializeRoot(Marshaller.java:118)
at org.eclipse.yasson.internal.Marshaller.marshall(Marshaller.java:74)
at org.eclipse.yasson.internal.JsonBinding.toJson(JsonBinding.java:98)
is the serializer hell-bent on using toString at this point?
I tried
public class Person {
private String name;
public Person(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
public class PersonAdapter implements JsonbAdapter{
#Override
public String adaptToJson(Person obj) throws Exception {
return obj.getName();
}
#Override
public Person adaptFromJson(String obj) throws Exception {
return new Person(obj);
}
}
public class Test {
public static void main(String[] args) {
Map<Person, Integer> data = new HashMap<>();
data.put(new Person("John"), 23);
JsonbConfig config = new JsonbConfig().withAdapters(new PersonAdapter());
Jsonb jsonb = JsonbBuilder.create(config);
System.out.println(jsonb.toJson(data, new HashMap<Person, Integer>() {
}.getClass().getGenericSuperclass()));
}
}
but still ended up with the toString() of Person
Thanks in advance,
Nik
https://github.com/eclipse-ee4j/yasson/issues/110 (in my case since that's the default provider for WildFly)

Vaadin: get reference of UI to change data

I want to change data inside a Vaadin UI. The change is invoked by a a rest call. There, i somehow need a reference to the UI class to call its method´, e.g. changeValue(string value).
I'm using vaadin-spring-boot-starter 1.0.0
Is that somehow possible?
EDIT: Another question now:
I was trying to do that Server Push, mentioned by #Eric, inside of a View, so that the view will get updated on a Broadcast message. However, this is not working (no exceptions, nothing to debug, just no updates in the view). This is what i do in my View:
#UIScope
#SpringView(name = LoadWebsiteView.VIEW_NAME)
#Push
public class LoadWebsiteView extends VerticalLayout implements View, Broadcaster.BroadcastListener {
...
#Autowired
public LoadWebsiteView(ScraperMainUI scraperMainUi) {
this.scraperMainUi = scraperMainUi;
Broadcaster.register(this);
initControlPane();
}
#Override
public void receiveBroadcast(String message) {
scraperMainUi.access(new Runnable() {
#Override
public void run() {
urlTxtField.setValue(message);
}
});
}
and here is the simple stuff i do in my restcontroller:
Broadcaster.broadcast(text);
What you are looking for is Vaadin's Push feature and a way to send a message to a list of registered "clients" (in this case, the Vaadin UIs who need to known about the changes).
You can read about Vaadin Push here: Enabling Server Push and also in the article Advanced Push
The Vaadin push function allows your server to force updates to the client instead of waiting on the browser to request again.
The message component simply acts as a way to tell subscribed UIs that there is an update they need to action.
This said, I have a project that does about the same as multiple users are actioning items and there are Spring scheduled tasks that also can effect changes the user needs to know about.
Note, the below examples are based on the examples available in Enabling Server Push article.
Broadcaster.java - Acts as the mechanism that registers instances to receive broadcasts and provides a facility to send broadcasts. In the below example, I have I have a class that represents a message (BroadcastMessage) but you could simplify it of course.
public class Broadcaster implements Serializable {
private static final long serialVersionUID = 3540459607283346649L;
static ExecutorService executorService = Executors.newSingleThreadExecutor();
private static LinkedList<BroadcastListener> listeners = new LinkedList<BroadcastListener>();
public interface BroadcastListener {
void receiveBroadcast(BroadcastMessage message);
}
public static synchronized void register(BroadcastListener listener) {
listeners.add(listener);
}
public static synchronized void unregister(BroadcastListener listener) {
listeners.remove(listener);
}
public static synchronized void broadcast(final BroadcastMessage message) {
for (final BroadcastListener listener: listeners)
executorService.execute(new Runnable() {
#Override
public void run() {
listener.receiveBroadcast(message);
}
});
}
}
Here is the class I defined for my BroadcastMessage. The idea is to have a way to denote what kind of message I have and also some payload in the form of a Map
public class BroadcastMessage implements Serializable {
private static final long serialVersionUID = 5637577096751222106L;
public BroadcastMessageType messageType;
public Map<String, String> params;
public BroadcastMessage() {
}
public BroadcastMessage(BroadcastMessageType messageType) {
this.messageType = messageType;
this.params = new HashMap<String, String>();
}
public BroadcastMessage(BroadcastMessageType messageType, Map<String, String> params) {
this.messageType = messageType;
this.params = params;
}
public BroadcastMessageType getMessageType() {
return messageType;
}
public void setMessageType(BroadcastMessageType messageType) {
this.messageType = messageType;
}
public Map<String, String> getParams() {
return params;
}
public void setParams(Map<String, String> params) {
this.params = params;
}
}
This is an example Vaadin UI that wants to listen for Broadcasts. Note the #Push annotation. Without this, the client will only refresh when the browser decides to. #Push makes it immediate**
#SpringComponent
#UIScope
#Push
#SpringView(name=TaskListComponent.NAME)
public class TaskListComponent extends MyCustomComponent implements Broadcaster.BroadcastListener, View {
/** PRUNED DOWN, TO DEMONSTRATE THE KEY CODE **/
// Register this window when we enter it
#Override
public void enter(ViewChangeEvent event) {
Broadcaster.register(this);
}
// Must also unregister when the UI expires
#Override
public void detach() {
Broadcaster.unregister(this);
super.detach();
}
// Receive a broadcast
#Override
public void receiveBroadcast(BroadcastMessage message) {
getUI().access(new Runnable() {
#Override
public void run() {
// DO WHATEVER YOU NEED TO DO HERE.
// I CALLED INITIALIZE BUT IT COULD BE
// JUST YOU FIELD UPDATE
if ( message.getMessageType().equals(BroadcastMessageType.REFRESH_TASK_LIST) )
initialize();
}
});
}
}
To send a message from your rest interface:
Broadcaster.broadcast(
new BroadcastMessage(
BroadcastMessageType.AUTO_REFRESH_LIST
)
);
Hope this helps! :)

Can't evict from Spring Cache in Guice DI app

I'm trying to use String Cache abstraction mechanism with guice modules.
I've created interceptors:
CacheManager cacheManager = createCacheManager();
bind(CacheManager.class).toInstance(cacheManager);
AppCacheInterceptor interceptor = new AppCacheInterceptor(
cacheManager,
createCacheOperationSource()
);
bindInterceptor(
Matchers.any(),
Matchers.annotatedWith(Cacheable.class),
interceptor
);
bindInterceptor(
Matchers.any(),
Matchers.annotatedWith(CacheEvict.class),
interceptor
);
Then, implemented Strings Cache interface and CacheManager, and finally annotated my DAO classes with #Cachable and #CacheEvict:
public class DaoTester {
QssandraConsumer qs;
#CachePut(value = "cached_consumers", key = "#consumer.id")
public void save(QssandraConsumer consumer) {
qs = consumer;
}
#Cacheable(value = "cached_consumers")
public QssandraConsumer get(String id) {
if (id != null) {
qs.getId();
}
return qs;
}
#CacheEvict(value = "cached_consumers", key = "#consumer.id")
public void remove(QssandraConsumer consumer) {
qs = consumer;
}}
Caching is simply fine - no problems here, but when i try to evict(calling remove method in this example), evrything crashes and I see:
Exception in thread "main" org.springframework.expression.spel.SpelEvaluationException: EL1007E:(pos 10): Field or property 'id' cannot be found on null
at org.springframework.expression.spel.ast.PropertyOrFieldReference.readProperty(PropertyOrFieldReference.java:205)
at org.springframework.expression.spel.ast.PropertyOrFieldReference.getValueInternal(PropertyOrFieldReference.java:72)
at org.springframework.expression.spel.ast.CompoundExpression.getValueInternal(CompoundExpression.java:57)
at org.springframework.expression.spel.ast.SpelNodeImpl.getValue(SpelNodeImpl.java:93)
at org.springframework.expression.spel.standard.SpelExpression.getValue(SpelExpression.java:88)
at org.springframework.cache.interceptor.ExpressionEvaluator.key(ExpressionEvaluator.java:80)
at org.springframework.cache.interceptor.CacheAspectSupport$CacheOperationContext.generateKey(CacheAspectSupport.java:464)
at org.springframework.cache.interceptor.CacheAspectSupport.inspectCacheEvicts(CacheAspectSupport.java:260)
at org.springframework.cache.interceptor.CacheAspectSupport.inspectAfterCacheEvicts(CacheAspectSupport.java:232)
at org.springframework.cache.interceptor.CacheAspectSupport.execute(CacheAspectSupport.java:215)
at org.springframework.cache.interceptor.CacheInterceptor.invoke(CacheInterceptor.java:66)
at qiwi.qommon.deployment.dao.DaoTester.main(DaoTester.java:44)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)
What's wrong here?!
BTW, cached object is:
public class QssandraConsumer implements Identifiable<String> {
private String id;
private String host;
#Override
public String getId() {
return id;
}
#Override
public void setId(String id) {
this.id = id;
}
public String getHost() {
return host;
}
public void setHost(String host) {
this.host = host;
}
#Override
public boolean equals(Object object) {
if (this == object) {
return true;
}
if (null == object) {
return false;
}
if (!(object instanceof QssandraConsumer)) {
return false;
}
QssandraConsumer o = (QssandraConsumer) object;
return
Objects.equal(id, o.id)
&& Objects.equal(host, o.host);
}
#Override
public int hashCode() {
return Objects.hashCode(
id, host
);
}
#Override
public String toString() {
return Objects.toStringHelper(this)
.addValue(id)
.addValue(host)
.toString();
}
}
Finally I figured out what was the reason of the problem:
when injecting a class that uses annotation(which are intercepted, like #Cachable or #CacheEvict) Guice enhances class (AOP make bytecode modification in runtime). So when CacheInterceptor tryed to evaluate key = "#consumer.id" it failed because couldn't find argument name in enhanced class (see: LocalVariableTableParameterNameDiscoverer#inspectClass).
So it will not work in Guice out of the box.
In spring the proxy class is created - so no problems here.

Resources