Session map is null when printed - session

I am working on JSF1.1 with JSP as presentation technology.
I have a managed bean with an ArrayList and I display the list in as rows.
Everything works fine. I have session replication with two server nodes and when I replicate the session, and put one of the cluster down, app is now on second cluster but the session attributes are lost.
I tried to print sessionMap using ExternalContext to see session attributes but that is null too.
What could be a possible reason?

The attributes are likely not Serializable. That's a requirement to get them to persist on disk and/or to transfer as bytes over network.
To fix this, just ensure that all session attributes (including session scoped managed beans) implement Serializable like this:
public class SomeSessionClass implements Serializable {
// ...
}
Don't forget to make any members Serializable as well whenever applicable. E.g.
public class SomeSessionClass implements Serializable {
private SomeNestedClass foo; // Has to implement Serializable as well!
// ...
}

Related

Understanding Redis inside Spring Boot

I have a Spring Boot application, where I need to get data from a table when the app initializes.
I have a repository with the following code:
#Repository
public interface Bookepository extends JpaRepository<Book, Integer> {
Proveedor findByName(String name);
#Cacheable("books")
List<Proveedor> findAll();
}
Then from my service:
#Service
public class ServiceBooks {
public void findAll(){
booksRepo.findAll();
}
public void findByName(String name){
booksRepo.findByName(name);
}
}
And then I have a class that implements CommandLineRunner:
#Component
public class AppRunner implements CommandLineRunner {
private final BookRepository bookRepository;
public AppRunner(BookRepository bookRepository) {
this.bookRepository = bookRepository;
}
#Override
public void run(String... args) throws Exception {
bookRepository.findAll());
}
}
So here,when the application initializes, it queries to the Books table and caches the result. Inside the application each time I call find.all(), the cache is working, and I get the data from my cache.
So here are my 2 questions:
About Redis, I am not using Redis and I am doing database cache without any problem. So, where does Redis fit into this approach? I don't understand why everybody uses Redis when cache is working without needing other libraries.
When I call findByName(name), is there any chance to execute that query over the data I already have cached? I know I can have a cache on that method, but the cache will save data each time I search a particular name. If a name is searched for the first time, it will go to the database for that value. I don't want that, I would like that Spring performs the query using the data from the first cache where I have all Books.
The answers to your question
Redis avoids the DB call as it stores your response in Memory. You can use #cacheable even in controller or service. If you use #cacheable in controller, your request will not even execute the controller method, if it is already cached.
for FindByName, Redis provides a nice way to store the data based on keys.
Refer the link Cache Keys.
Once you request by Name, it will get the data from DB, the next time you request with same name, it will get from cache based on the key.
Coming back to your question, NO you should not do a search on your cached data, as caches are highly volatile, you cannot trust the data from cache. also searching through the cached data might affect the performance and you might need to write lines of unneeded additional code.
Spring boot manages the cache per application or per service. When you are using multiple instance of a service or app then certainly you'll want to manage the cache centrally. Because per service cache is not usable in this case because what one app caches in its own spring boot is logically not accessible by another apps.
So here Redis comes into picture. If you use Redis, then each instance of service will connect to the same Redis cache and get the same result.

How to synchronize two session scoped beans in JSF?

I have this case where I have two session-scoped beans. One is used for Login-functionality. So this bean remembers what the current user is, which it sets after a user has successfully logged in.
There is another session scoped bean that allows the user to configure some stuff, which is also supposed to be be kept along the session. The user can go back to the configuration-site whenever he wants and see his old (from the same session) data. Important to know is that the user does not need to be logged in to use this site. Imagine like a cart on a webshop, with many shops you can put stuff in the cart before even logging in and it will remain throughout your session.
Here is where it gets tricky: On this configuration-site, the user can access some special functionality, such as permanently saving his configuration-stuff, but only if he is logged in. If not, he simply won't have the option. Again, very similar to a webshop, if you actually want to order the cart of your session you usually have to log in at that point.
The problem is that if the user first goes onto the configuration-site, then this session bean will be created first. The session bean retrieves the user by a binding-annotation (CurrentUser) which is #Provided by the Login-Bean via it's getter for the current user.
However, at creation time of the configuration-site bean, there is no current user.
Now, if the user then decides to go and login, the configuration-site bean will still think that there is no currentUser, since that field was initialized when the bean was initialized and there is no logic that will update it.
How can I handle this situation? Do I have to start manually putting and retrieving stuff from the Session-Objects? So far everything was handled automatically by JSF / Application Server simply because of the #SessionScoped annotations.
Edit: Here goes some code to explain the situation further:
The Login-Bean:
#SessionScoped
#Named
public class LoginUserManager implements Serializable {
private UserBean currentUser;
// Logic that does the login and set the currentUser if successfull
// ...
// "Produces" currentUsers for other beans, that want to inject it simply
// via the #CurrentUser annotation, see below
#Produces
#CurrentUser
public UserBean getCurrentUser() {
return currentUser;
}
}
Then there is the configuration-manager
#SessionScoped
#Named
public class ConfigurationManager implements Serializable {
// Session based configuration data here
// And, the current user (if any)
#CurrentUser
private UserBean currentUser;
}
The CurrentUser annotation should be a simple "binding annotation" if I understood correctly. It's taken from a snippet I saw on the internet, to be honest. I found it elegant, thought it's smooth to read and functionally identical to injecting the LoginUserManager directly and then calling it's getCurrentUser() getter.
#Retention(RUNTIME)
#Target({TYPE, METHOD, FIELD})
#BindingType
public #interface CurrentUser {
}

Spring-boot with eclipseLink transaction issue

I have implemented EntityListener in eclipseLink. My app is built using spring-boot , spring-data and eclipseLink. I have a requirement of inserting record in 2 table (Audit tables) when data in inserted in 1 table. I have got EntityManager in my Listener and everything seems to works normally. When I debug the code I can see that entities which I am going to save are having "id" generated from the sequence which is maintained at DB level. BUT when the transaction is committed I see only main table data but audit tables data is not getting committed. Here is the sample code :
#Entity
#Table(name="MyTable")
#EntityListeners(MyTableListener.class)
public class MyTable implements Serializable{
private static final long serialVersionUID = -5087505622449571373L;
private Long id;
// Rest of the fields
#Id
#GeneratedValue(strategy=GenerationType.SEQUENCE, generator="MASTER_SEQ")
#SequenceGenerator(name="MASTER_SEQ",sequenceName="MASTER_SEQ",allocationSize=1)
public Long getId() {
return id;
}
// Getters/Setters
}
Listener code :
public class MyTableListener extends DescriptorEventAdapter {
#Override
public void postInsert(DescriptorEvent event) {
MyTable msg = (MyTable)((InsertObjectQuery) event.getQuery()).getObject();
EntityManager em = BeanUtil.getBean(EntityManager.class);
MyAudit statusAudit = new MyAudit();
statusAudit.setNewVal("NEW");
statusAudit.setOldval(null);
statusAudit.setTargetColumnName(targetColumn);
statusAudit.setTargetRecordId(msg.getId());
em.persist(statusAudit);
}
}
Nothing seems to be wrong with the code. BUT when I see in the set the sql logs to "FINEST" , I can see that insert queries are not being fired for audit tables.
I have been dealing with this problem for more than 2 days and dont understand what exactly is wrong. Please help me.
You are never calling flush on the EntityManager. I suspect something like the following is going on:
You add your domain entities to the EntityManager, possibly through Spring Repositories.
Something triggers a flush, possibly the transaction handling of Spring.
Your domain entities get flushed.
Your event listener gets triggered.
You add audit entities to the EntityManager, but those never get flushed.
The database connection gets a commit. Saving everything but your audit trail.
If this theory ist correct, which you should be able to verify through the logs and debugger, you can probably fix it, by adding a call to flush in your listener.
As you described in the comments this causes further problems, which happen because you are trying to do something which you are not supposed to be doing.
According to this article, the JPA spec does not allow usage of the entitymanager inside callback events.
In general, the lifecycle method of a portable application should not invoke EntityManager or Query operations, access other entity instances, or modify relationships within the same persistence context. A lifecycle callback method may modify the non-relationship state of the entity on which it is invoked.
So looks, like we are stuck here, so you probably should consider a completely different approach like EclipseLink History tables.

Accessing Spring #Transactional service from multiple threads

I would like to know if the following is considered safe.
Usual Spring service class that accesses a bunch of DAOS / hibernate entities:
#Transactional
public class MyService {
...
public SomeObject readStuffFromDB(String key) {
...
//return some records from the DB via hibernate entity etc
}
A class in the application that has the service wired in:
public class ServiceHolder {
private MyService myService;
private SomeOtherObject multiThreadedMethod() {
...
//calls myService.readStuffFromDB() and uses the results
//to return something useful
}
multiThreadedMethod will be called from multiple threadpool threads. I would like to know if the multiThreadedMethod is safe in its calls to myService.
It is NOT making any modifications to the DB - only reading.
What happens if two threads call myService.readStuffFromDB() at exactly the same time? Will a concurrent modification exception be thrown from somewhere?
I've been running it with no issues but I'm not 100% sure it will always work.
Yes you will call the same object in the same time as long as your service bean is defined as singleton (which is default and proper), but you should not rely on local variables in you services. So the methods should be written that way they can work independently (you don't need a mutual exclusion here). If you called db and tried do any operations nothing would happen because every thread would receive a new instance of entity manager. If you modified db in the same time and any type of db exception was thrown you would get a rollback exception which is perfectly fine.
entityManager.persist() will do more or less entityManager.getEntityManagerAssignedToCurrentThread().persist()
It is a proxy not real object. So you are safe :)

session is getting reset in IBM Websphere Commerce

I am setting a session in the jsp using scriplet in IBM WCS and setting a value here but when reloading the page the session value is getting lost .
here is how I am setting session attribute
<%
session.setAttribute("testMap", testValue);
%>
However on my local toolkit Its works fine ,but when it is deployed to server having this issue
Please suggest any solution regarding this
Thanks
Ankit
Session state in Websphere Commerce is saved in the Business Context, which is tied to the users ActivityToken.
Session state is serialized to the database, and will be available if the users session goes to another server in the cluster.
You can add your own session state by registering a new context element in BusinessContext.xml in the WC\xml\config\BusinessContext.xml, like so:
<BusinessContext ctxId="MyContext"
factoryClassname="com.ibm.commerce.context.factory.SimpleBusinessContextFactory" >
<parameter name="spiClassname" value="com.myorg.commerce.context.contentimpl.MyContextImpl" />
Then you need to tell which kinds of sessions your Context will be present in
<!-- web site store front configuration -->
<InitialBusinessContextSet ctxSetId="Store" >
...
<InitialBusinessContext ctxId="MyContext" createOrder="0" />
The context will be created along with all other contexts, and will be serialized to either the CTXDATA database table (for known users) and in a browser cookie for anonymous users.
Your context class should look something like this:
An interface class com.myorg.commerce.context.mycontextimpl.MyContext
public abstract interface MyContext extends Context
{
public static final String CONTEXT_NAME = "com.myorg.commerce.context.mycontextimpl.MyContext";
public abstract String getSomeValue();
public abstract void setSomeValue(String v);
}
And an implementation
public class MyContextImpl extends AbstractContextImpl
implements MyContext
{
}
After setting a new value, use "this.setDirty(true)" to flag the changes for persistance.
You must also override getContextAttributes to return the values of your context that needs to be serialized, and the setContextAttributes to re-establish the values.
The point is, that the context does more than simply store values. You put invariants in the context, that should hold true for all aspects of the users interaction with the site. The best example is the EntitlementContext, which holds which contract(s) you are buying under, which can be rather complicated to calculate.
Anyway, to access your context from a command, you'd use
this.getCommandContext().getContext(MyContext.CONTEXT_NAME);
And from a jsp
if (request.getAttribute("myContext") == null) {
request.setAttribute("myContext", ((CommandContext) request.getAttribute("CommandContext")).getContext(MyContext.CONTEXT_NAME));
}
after which you can use it as
${myContext.someValue}
The short answer is don't do this. WebSphere commerce is typically deployed in a distributed environment, and you might be seeing the effect of this when your code gets deployed. It is a lot of work for the application to persist the session across WebSphere nodes. Instead use a cookie, or create a database table. What are you trying to store in that map that has to be in session.

Resources