Grails session-scoped Service throwing NotSerializable Exception - session

I have a Grails 3 application (3.1.1) that implements a Breadcrumb system. I based it on this plugin for an earlier version of Grails.
It runs fine locally (using Grails command line command run-app), however, when I build and run on Tomcat 7, I get the following exception:
Jul 08, 2016 5:10:34 PM org.apache.catalina.ha.session.DeltaManager requestCompleted
SEVERE: Unable to serialize delta request for sessionid [6605EAC9C04DF7E2512493CABDFB1AD2]
java.io.NotSerializableException: au.packagename.BreadCrumbService
The above named service has a scope set to session, and is specified as a proxy. I have even added the Serializable implementation, however that does not seem to help.
class BreadCrumbService implements Serializable {
static transactional = false
static scope = 'session'
static proxy = true
}
I have an Interceptor that uses the Service to write the current controller and action as a Crumb object to the session. I have added the Serializable implementation to the Crumb and BreadCrumbType Enum (used in the Controllers annotation) that gets written to the session.
Is anyone able to indicate to me why this might be happening (I understand the concept of Serializable) and how I might go about resolving it?

#Hoàng Long's comment put me the right track.
When writing the Crumb object (all of which were made Serializable) to the session, I was using a static variable in the BreadCrumbService for the session map's key.
session[BreadCrumbService.NAMESPACE].crumb = new Crumb()
When I moved this variable to the Crumb object, the issue was resolved.
Even though the Service itself hasn't being written to the session. The mere reference to a variable inside the Service in the writing to the session required the service and every member to be Serializable.

Related

how to Resolve "could not initialize proxy - no session" error when using Spring repository

I'm working on a mutitenant project it maintains different schema for each tenant, followed Project
As we are dynamically switching the tenants so it looks like some configuration is missed which is closing the session or not keeping the session open to fetch the LAZY loaded objects. Which results in "could not initialize proxy - no session" error.
Please check below link to access the complete project and db schema scripts, please follow the steps given in Readme file.
Project
It will be helpful if someone can point out the issue in the code.
i tried to put service methods in #Transactional annotation but that didn't work.
I'm expecting it to make another call to the LAZY loaded object, This project is simplefied verson of the complex project, actually i have lot more lazy loaded objects.
Issue:-
I'm getting no Session error "could not initialize proxy [com.amran.dynamic.multitenant.tenant.entity.Tenant#1] - no Session"
at line 26 (/dynamicmultitenant/src/main/java/com/amran/dynamic/multitenant/tenant/service/ProductServiceImpl.java)
The issue is that your transaction boundaries are not correct. In TenantDatabaseConfig and MasterDatabaseConfig you've correctly added #EnableTransactionManagement, which will setup transactions when requested.
However - the outermost component that has an (implicit) #Transactional annotation is the ProductRepository (by virtue of it being implemented by the SimpleJpaRepository class - which has the annotation applied to it - https://github.com/spring-projects/spring-data-jpa/blob/864c7c454dac61eb602674c4123d84e63f23d766/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/SimpleJpaRepository.java#L95 )
and so your productRepository.findAll(); call will start a transaction, create a JPA session, run the query, close the session, close the transaction, which means that there is no longer any transaction / session open in which to perform the lazy-loading.
Therefore, your original attempt of
i tried to put service methods in #Transactional annotation but that didn't work.
IS the correct thing to do.
You don't say exactly what you tried to do, and where, but there are a few things that could have gone wrong. Firstly, make sure you're adding a org.springframework.transaction.annotation.Transactional and not a javax.transaction.Transactional annotation.
Secondly (and the more likely problem in this scenario), you'll need to configure the annotation with which transaction manager the transaction should be bound to, otherwise it may use an existing / new transaction created against the master DB connection, not the tenant one.
In this case, I think that:
#Service
#Transactional(transactionManager = "tenantTransactionManager")
public class ProductServiceImpl implements ProductService {
should work for you, and make all the methods of the service be bound to a transaction on the tenant DB connection.
EDIT: Answering a follow-up question:
can you please also suggest a better way to inject my tenantTransactionManager in all my service classes, as I don't want to mention tenantTxnManger in all service classes if there is any better way to do it ?
Yes, sure. You can create a meta-annotation that applies multiple other annotations, so you could create:
/**
* Marks class as being a service operating on a single Tenant
*/
#Target(ElementType.TYPE)
#Retention(RetentionPolicy.RUNTIME)
#Service
#Transactional("tenantTransactionManager")
public #interface TenantService {
}
and then you can simply annotate your service classes with #TenantService instead of #Service:
#TenantService
public class ProductServiceImpl implements ProductService {

com.sap.cloud.sdk.frameworks.hystrix.ScpNeoHystrixBootstrapListenerjava.lang.IllegalStateException

If I use ODataQueryBuilder in a servlet, I can call the servlet without any problem.
If I incorporated the code in a method and call this method within a ServletContextListener, I got first the following error.
2018 02 27 13:17:09#+00#ERROR#org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/]##anonymous#fs-watcher#na#afc186d33#firstapp#web##na#na#na#na#Exception sending context initialized event to listener instance of class com.sap.cloud.sdk.frameworks.hystrix.ScpNeoHystrixBootstrapListenerjava.lang.IllegalStateException: Another strategy was already registered.
at com.netflix.hystrix.strategy.HystrixPlugins.registerConcurrencyStrategy(HystrixPlugins.java:190)
at com.sap.cloud.sdk.frameworks.hystrix.ScpNeoHystrixBootstrapListener.bootstrap(ScpNeoHystrixBootstrapListener.java:43)
at com.sap.cloud.sdk.frameworks.hystrix.ScpNeoHystrixBootstrapListener.contextInitialized(ScpNeoHystrixBootstrapListener.java:74)
at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:5110)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5633)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:145)
at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:1015)
at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:991)
at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:652)
at org.eclipse.gemini.web.tomcat.internal.TomcatServletContainer.startWebApplication(TomcatServletContainer.java:125)
at org.eclipse.gemini.web.internal.StandardWebApplication.start(StandardWebApplication.java:109)
at org.eclipse.gemini.web.extender.WebContainerBundleCustomizer.addingBundle(WebContainerBundleCustomizer.java:49)
at org.osgi.util.tracker.BundleTracker$Tracked.customizerAdding(BundleTracker.java:467)
at org.osgi.util.tracker.BundleTracker$Tracked.customizerAdding(BundleTracker.java:1)
at org.osgi.util.tracker.AbstractTracked.trackAdding(AbstractTracked.java:256)
at org.osgi.util.tracker.AbstractTracked.track(AbstractTracked.java:229)
at org.osgi.util.tracker.BundleTracker$Tracked.bundleChanged(BundleTracker.java:443)
at org.eclipse.osgi.framework.internal.core.BundleContextImpl.dispatchEvent(BundleContextImpl.java:847)
at org.eclipse.osgi.framework.eventmgr.EventManager.dispatchEvent(EventManager.java:230)
at org.eclipse.osgi.framework.eventmgr.ListenerQueue.dispatchEventSynchronous(ListenerQueue.java:148)
at org.eclipse.osgi.framework.internal.core.Framework.publishBundleEventPrivileged(Framework.java:1568)
at org.eclipse.osgi.framework.internal.core.Framework.publishBundleEvent(Framework.java:1504)
at org.eclipse.osgi.framework.internal.core.Framework.publishBundleEvent(Framework.java:1499)
at org.eclipse.osgi.framework.internal.core.BundleHost.startWorker(BundleHost.java:391)
at org.eclipse.osgi.framework.internal.core.AbstractBundle.start(AbstractBundle.java:300)
at org.eclipse.osgi.framework.internal.core.AbstractBundle.start(AbstractBundle.java:292)
at org.eclipse.virgo.web.war.deployer.WARDeployer.start(WARDeployer.java:780)
at org.eclipse.virgo.nano.deployer.internal.StandardApplicationDeployer.startDeployables(StandardApplicationDeployer.java:325)
at org.eclipse.virgo.nano.deployer.internal.StandardApplicationDeployer.bulkDeploy(StandardApplicationDeployer.java:116)
at org.eclipse.virgo.nano.deployer.hot.HotDeploymentFileSystemListener.bulkDeployIfNotDeployed(HotDeployerFileSystemListener.java:143)
at org.eclipse.virgo.nano.deployer.hot.HotDeploymentFileSystemListener.onInitialEvent(HotDeployerFileSystemListener.java:105)
at org.eclipse.virgo.util.io.FileSystemChecker.notifyListenersOnInitialEvent(FileSystemChecker.java:207)
at org.eclipse.virgo.util.io.FileSystemChecker.handleInitialFiles(FileSystemChecker.java:177)
at org.eclipse.virgo.util.io.FileSystemChecker.check(FileSystemChecker.java:261)
at org.eclipse.virgo.nano.deployer.hot.WatchTask.run(WatchTask.java:49)
at java.lang.Thread.run(Thread.java:807)
Followed by:
One or more listeners failed to start. Full details will be found in
the appropriate container log file
Context [] startup failed due to previous errors
This will destroy my Servlet Context Listener and then failed to start web application in NEO.
It is strange because the method is called well and in the log I can see that the method is called without an error.
If I don't call the method in code, the application is starting up well.
Please let me know, how I can solve this issue, because I need to call the S/4 Hana system.
Update:
Version 2.0.0 of the SAP S/4HANA Cloud SDK changed the way how RequestContextListeners are initialized. It is now be possible to use the following code without additional effort:
new RequestContextExecutor().execute(...);
Original answer:
I guess that you want to run logic in some background task that is not triggered by a user request.
Can you try to wrap the logic calling the S/4HANA system in a Callable which is passed to the execute method of a RequestContextExecutor?
For example:
List<SomeData> result = new RequestContextExecutor()
.execute(new Callable<List<SomeData>>() {
#Override
public List<SomeData> call() {
return new GetSomeDataCommand().execute();
}
});
Note that this will require a technical user with Basic credentials in the destination configuration; principal propagation is not available in this case.
Also note that if you want to run the background task calling the external system in a ServletContextListener during application startup, you have to
either explicitly register the relevant RequestContextListener classes which are also subclasses of ServletContextListener (including, if you are using the SAP Cloud Platform Neo environment, initializing the ScpNeoHystrixBootstrapListener),
or specify the order of the ServletContextListener classes explicitly in the web.xml file.
You can register these listeners explictly as follows:
// ensure that the correct HystrixConcurrencyStrategy is used
new ScpNeoHystrixBootstrapListener().bootstrap();
// explicitly register RequestContextListeners
new RequestContextExecutor().withListeners(
new DestinationsRequestContextListener(),
new ScpNeoDestinationsRequestContextListener(),
new TenantRequestContextListener(),
new UserRequestContextListener()
).execute( /* callable */ );

Jersey Exception Java 1.8

I am calling a REST service and the provider has supplied a client. Client's specification is to use Jersey 2.18. So i have used the below jersey dependencies
Jersey-client-2.18.jar
Jersey-common-2.18.jar
Jersey-entity-filtering-2.18.jar
Jersey-guava-2.18.jar
jersey-media-json-jackson-2.18.jar
I am making calls using scheduledThreadPoolExecutor and my application is running in tc server and JDK 1.8. Sporadically i get the below exception. I tried searching this exception in google but no luck. But i see the below for almost everytime
Cannot create new registration for component type class > org.glassfish.jersey.client.authentication.HttpAuthenticationFeature
Exception
java.lang.NullPointerException at
org.glassfish.jersey.model.internal.CommonConfig.configureFeatures(CommonConfig.java:694)
at
org.glassfish.jersey.model.internal.CommonConfig.configureMetaProviders(CommonConfig.java:644)
at
org.glassfish.jersey.client.ClientConfig$State.configureMetaProviders(ClientConfig.java:365)
at
org.glassfish.jersey.client.ClientConfig$State.initRuntime(ClientConfig.java:398)
at
org.glassfish.jersey.client.ClientConfig$State.access$000(ClientConfig.java:88)
at
org.glassfish.jersey.client.ClientConfig$State$3.get(ClientConfig.java:120)
at
org.glassfish.jersey.client.ClientConfig$State$3.get(ClientConfig.java:117)
at
org.glassfish.jersey.internal.util.collection.Values$LazyValueImpl.get(Values.java:340)
at
org.glassfish.jersey.client.ClientConfig.getRuntime(ClientConfig.java:726)
at
org.glassfish.jersey.client.ClientRequest.getConfiguration(ClientRequest.java:285)
at
org.glassfish.jersey.client.JerseyInvocation.validateHttpMethodAndEntity(JerseyInvocation.java:126)
at
org.glassfish.jersey.client.JerseyInvocation.(JerseyInvocation.java:98)
at
org.glassfish.jersey.client.JerseyInvocation.(JerseyInvocation.java:91)
at
org.glassfish.jersey.client.JerseyInvocation$Builder.method(JerseyInvocation.java:411)
at
org.glassfish.jersey.client.JerseyInvocation$Builder.get(JerseyInvocation.java:307)
I resolved this issue. My implementation was wrong. The client object was defined as a class level variable and it was initialized during every method call. During parallel call. every thread concurrent call attacks the same class level object and tries to modify and hence the object was not properly initialized. Now i fixed it by injecting the class from spring so that it is not modified during every call.

How to get request info on session created in Spring MVC?

I'm hoping to save some client info (IP address, etc) to a database on session created in Spring MVC.
I created a class implementing HttpSessionListener and configured it in web.xml. However, I'm not sure where to go after that.
Would like to be able to inject a bean as well (Spring Data JPA repository).
I've seen How to get the IP address when a session is created? , however if I try to access RequestContextHolder.currentRequestAttributes() I get the following exception:
SEVERE: Session event listener threw exception
java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
You can create a bean this way with Spring java config:
#Bean
#Named ("IP")
#Scope ("session")
public String ip (HttpServletRequest request) {
return request.getRemoteAddr ();
}
If all you want to do is log stuff then you should use the HttpSessionListener, please provide your source and full stack trace. Use pastebin.com if necessary.

Using a Stateful Session Bean to track an user's session

it's my first question here and I hope that I'm doing it right.
I need to work on a Java EE project, so, before starting, I'm trying to do something simple and see if I can do that.
I'm stuck with Stateful Session Beans.
Here's the question :
How can I use a SFSB to track an user's session?
All the examples that I saw, ended up in "putting" the SFSB into a HttpSession attribute.
But I don't understand why!
I mean, if the bean is STATEFUL, why do I have to use the HttpSession to keep it?
Isn't an EJB Container's task to return the right SFSB to the client?
I've tried with a simple counter bean.
Without using the session, two different browsers have the same counter bean (clicking on "increment" changed the value for both of them).
Using session, I have two different values, each for every browser (clicking on "increment" on Firefox, added one just to Firefox's bean).
But my teacher told that a SFSB keeps the "conversational state with a client", so why it doesn't just work without using a HttpSession ?
If I understood correctly , isn't using HttpSession with a SFSB the same of doing it with a SLSB instead?
I hope that my question(s) is clear and that my English is not that poor!
EDIT :
I'm working on a login system.
Everything goes fine and after completing the login it takes me to a profile page that show user's data.
But reloading the page makes my data disappear!
I've tried adding HttpSession while logging but doing in this way makes the data stay even after the logout!
A Stateful Session Bean (SFSB) has to be combined with the HTTP session in a web environment, since it's a pure business bean that itself knows nothing about the web layer.
Traditionally EJBs even mandatory lived inside their own module (the EJB module), that couldn't even access web artifacts if they wanted to. This is an aspect of layered systems. See Packaging EJB in JavaEE 6 WAR vs EAR for more information about that.
The original clients for Stateful Session Beans were among others Swing desktop applications, that communicated with the remote EJB server via a binary protocol. A Swing application would obtain a connection to a remote Stateful Session Bean via a proxy/stub object. Embedded in this proxy is an ID of some kind that the server can associate with a specific SFSB. By holding on to this proxy object, the Swing client can make repeated calls to it and those will go to the same bean instance. This will thus create a session between the client and the server.
In the case of a web application, when a browser makes an initial request to a Java EE web application it gets a JSESSIONID that the server can associate with a specific HTTPSession instance. By holding on to this JSESSIONID, the browser can provide it with each followup request and this will activate the same http session server-side.
So, those concepts are very similar, but they do not automatically map to each other.
The browser only gets the JSESSIONID and has no knowledge about any SFSB ID. Unlike the Swing application, the browser communicates with web pages, not directly with Java beans.
For mapping the client's request to a specific stateful session bean, the EJB container only cares about the ID provided via the SFSB proxy. It can't see if the call happened to originate from code in the web module and can't/shouldn't really access any HTTP contexts.
The web layer being the client code that accesses the SFSB must 'hold on' to a specific proxy reference. Holding on to something in the web layer typically means storing it in the HTTP session.
There is however a bridge technology called CDI that can make this automatic connection. If you annotate your SFSB with CDI's #SessionScoped and obtain a reference to the SFSB via CDI (e.g. using #Inject), you don't have to manually put your SFSB into the http session. However, behind the scenes CDI will do exactly that anyway.
You need to define the bean with #SessionScoped instead of #RequestScoped (if you are looking for HttpSession equivalent solution)
something like
#SessionScoped
public class SessionInfo implements Serializable{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Have a look at following (explained in detail)
http://www.oracle.com/technetwork/articles/java/cdi-javaee-bien-225152.html

Resources