session attributes getting replicated for different user sessions - java

I am building an online hotel reservation system. for that I am using a reservation cart in which I keep track of rooms added by the user. When I am adding some rooms in a browser login in with user1 , now when I log in with some other browser with user2 and add some other rooms in the cart. Now when I try to add another room in cart of user1 , the existing cart of user1 gets replaced by the cart values of user2. I am maintaining different sessions for each user but the cart attribute is getting same for all the sessions . I am currently working on local host. please help
this is how I am adding values to rbList and setting the session attribute.
if(request.getParameter("button").equals("addRoom"))
{ // System.out.println("******************inside addRoom*****************");
if(session!=null)
{
availableRooms = (ArrayList<HotelBean>)session.getAttribute("availableRooms");
int addPos = Integer.parseInt(request.getParameter("roomPosition"));
rb = availableRooms.get(addPos);
String roomID = rb.getRoomId();
HoteDAO hd = new HoteDAO();
boolean available = hd.isAvailable(roomID);
if(available){
if((ArrayList<HotelBean>)session.getAttribute("ReservationCart") == null){
rbList = new ArrayList<HotelBean>();
}
if(rbList == null){
rbList = new ArrayList<HotelBean>();
}
rbList.add(rb);
for(HotelBean room : rbList){
System.out.println(room.getRoomId());
}
session.setAttribute("ReservationCart",rbList);
RequestDispatcher rd=request.getRequestDispatcher("/AvailableRooms.jsp");
rd.forward(request,response);
}
else
{
System.out.println("Sorry the room is not available now");
RequestDispatcher rd=request.getRequestDispatcher("/AvailableRooms.jsp");
rd.forward(request,response);
}
}
}

Your last comment is the answer to your problem. You instantiate the rbList in a class that has only one instance across your web application. Hence you only have only one rbList accross all customers and that causes your problem.
Although I do not have a very clear picture of how your rbList work, I am confident that each customer should have their own unique rbList or at least their own cart.
Also, declaring the customer cart in a controller seems like a poor design choice.
The way that I would go about your problem would be create a separate CartModel class that contains everything cart related.
Create a one to one or one to many relationship from your CustomerModel to your CartModel.
Preferably save the CartModel(s) to your database or at session if your prefer to go with this design.
I hope I helped.

Related

Excatly how to test? (Unittest, JUnit, PhpUnit)

Well this question might be too localized.
Lets suppose I have forum system to test. Lets delete an user and his posts. Let me use a pseudo-code for the sake of simplificity:
class User
{
function add() { ... }
function delete (userID)
{
container::getOrCreateUserPostObject.deletePostsByUserID (userID)
DELETE FROM users WHERE ID = userID
}
}
class UserPost
{
function deletePostsByUserID (userID)
{
DELETE FROM posts WHERE USERID = userID
}
}
this now must be tested:
function testDeleteUser()
{
container::getOrCreateUserObject.add();
container::getOrCreateUserObject.add();
container::getOrCreateUserObject.delete (1)
// now check in the DB that how many records left, really one was deleted etc.
}
another test
function testDeletePosts
{
container::getOrCreateUserPostObject.deletePostsByUserID (1);
// again, now check in the DB that how many records left, really one was deleted etc.
}
this looks OK so far. The user deletion and user posts deletion works, and their test standalone.
Yes, standalone. We checked if its OK to delete an user and checked if its OK to delete his post. We didnt check if we delete an user with his posts works! There are two good working "lego" elements but is that OK if we put them together?
If I put this "global" test to testDeleteUser() then I repeat the post-deletion test code...
I don't know if i get you right, but in a test, you should not really rely on specific user id's like you are doing in testDeletePosts(), you should rather add a user here as well, add some posts, and delete these posts again. So your test is completely independent.
Update:
Something like this for checking the referential integrity
function testDeleteUsersAndPosts
{
addedUsers[0] = user.add();
addedPosts[0] = post.add(addedUsers[0], 'first Post')
addedPosts[1] = post.add(addedUsers[0], 'second Post')
addedUsers[1] = user.add();
addedPosts[2] = post.add(addedUsers[1], 'third Post for the second user')
// Check how many posts you have
allPosts = post.get().count()
for (id in addedUsers)
{
user.delete(id)
}
// Check how many posts you have now
allPostsNow = post.get().count();
return allPostsNow == (allPosts -3)
}
And something like this for checking the Post deletion only
function testDeletePosts
{
userID = user.add();
addedPost = post.add(userID, 'first Post')
// Check how many posts you have
allPosts = post.get().count()
post.delete(addedPost)
return post.get(addedPost) == false
}

Java Group Chat Application: Knowing if groups have users currently active

For the past 2 weeks, I have been working on a java group chat application. So far a user can login and join groups created by other users. The user can also send chat messages to each other inside of each group. The message distribution is handled by a server and the server only sends the chat messages to clients of the group from which it was sent. A list of groups which the user is a part of is also displayed, and I would like for there to be a small green mark(or anything else to notify the user) to let the user know if there are other users currently active on that chat room group.
Here is how my groups are stored in the database
**TABLE groups**
- id
- user_count
**TABLE group_members**
- groupid
- userid
The sending and receiving of chat messages are handled using sockets, and none of the sent messages are stored on the database. I was thinking of maybe having a field in the groups table where every time a user joins would increment the value in it by 1 and every time a user leaves, the value goes down by 1. This way if the number stored in this field is 0, there are no current users on here. I think there may be a better way to handle this though.
You could have an arraylist for every group that holds the names of every player in that group. Then you could easily get the names of people in the group and the number of people in it. so if you have a class named Group you could have something like:
class Group {
private ArrayList<String> users; // or instead of String if you have a User class use that
public Group(Type par) {
users = new ArrayList<String>();
}
public static void addUser(String userName) {
users.add(userName);
updateUsers();
}
public static void removeUser(String userName) {
for(int i = 0; i < users.size(); i++) {
if(users.get(i).equalsIgnoreCase(userName)) {
users.remove(i);
}
}
updateUsers();
}
public static int getNumberOfUsers() {
return users.size();
}
public static void updateUsers() {
for(String e : users) {
// send the user the necessary info to all users in the group
}
}
}
I just went with my idea as stated in the question. Works well and fast enough for my needs. heres how the database looks
TABLE groups
id
user_count
activity <--- this is where the values are increased or decresed.
TABLE group_members
groupid
userid

Reloading a datatable with values from database

I currently have a data table that displays a list of Users obtained from my database (Users Table). My application allows me to do the following:
Select a Group
Select a User
Add
UserGroups datatable displays the Group and User that was added.
The User that is added, will not be displayed in the User data table -- meaning to say, it is only in the view that the user will not be displayed. However, the user still exists in the database table.
(This is happening in my web view)
For example:
Group:
1. Web
2. Projects
3. Management
User:
1. Tom
2. Jane
3. John
I select 1 group and 1 user, and add it to the User Group.
UserGroup:
1. Management, John
AND User and Group tables shows the following:
Group:
1. Web
2. Projects
3. Management
User:
1. Tom
2. Jane
How would I refresh the User table, so that I can obtain a new list of Users from my database for another round of selection ?? because once I add all the Users, the User table is empty, and I want the User datatable to refresh, when I click on a new Group for selection.
Any clues or suggestions on how I might go about doing so... I am clueless.
I currently have the following methods in my managedBean:
My methods for retrieving a list of Users, Groups and UserGroups.
public List<Usuarious> getListOfUsuarios() throws DAOExceptions{
List<Usuarious> usuariosList = userDAO.list();
listOfUsuarios = usuariosList;
return listOfUsuarios;
}
public List<Grupos> getListOfGrps() throws DAOExceptions {
List<Grupos> grpList = grpDAO.list();
listOfGrps = grpList;
return listOfGrps;
}
public List<UsuariousGrupos> getListOfUserGroups() throws DAOExceptions{
List<UsuariousGrupos> usuariosGruposList = userGrpDAO.list(var2);
listOfUserGroups = usuariosGruposList;
return listOfUserGroups;
}
I thought of just creating a refreshList() method:
public void refreshList() throws DAOExceptions{
listOfUsuarios = getListOfUsuarios();
}
And then adding it to my finishAddUser() method list to refresh the datatable:
public void finishAddUsuariosGrupos()throws DAOExceptions {
this.userGroups.setId_grupo(var2);
this.userGroups.setId_usuario(var1);
userGrpDAO.create(userGroups);
refreshList();
}
But it is not working out.
I had a similar datatable refresh issue. I solved it by adding settimeout to the datatable:
<webuijsf:table onClick="setTimeout('#{user$reports.updateGeneratedReportList()}',500);"/>
updateGeneratedReportList is method is equal to your refreshList method.

functional test in playframework fails when adding items to cart

I wrote a functional test to check adding items to a shopping cart.For a user to be able to add items to cart,he needs to login.So,I created a method to login the user and another method to add the item.Before and after the addtocart method in test,I am checking the size of content of cart.The addtocart functionality works without any problem when I run the app in dev mode(I can check the db too-which is postgres and not an in memory db).The addtocart fails in test.
the controller method which adds item to cart
public static void addItemToCart(Long productId,Long cartId,String quantity) {
Product product = Product.findById(productId);
ShopCart cart = ShopCart.findById(cartId);
int qty = Integer.parseInt(quantity);
CartItem cartItem = new CartItem(product,qty);
cart.addItem(cartItem);
cart.save();
System.out.println("Controller::addItemToCart()::cart id="+cart.id+" has="+cart.cartItems.size()+" items);
}
my test method is
#Test
public void testUserCanAddItemsToCart() {
Fixtures.loadModels("data.yml");
User user = User.find("byEmail","user#shop.com").first();
loginAsCustomer("user#shop.com","userpass");
ShopCart usercart = new ShopCart(user);
usercart.save();
System.out.println("BEFORE ADD::usercart="+usercart.id+" has :"+usercart.cartItems.size()+" items");
assertTrue(usercart.cartItems.size()==0);
addItemsToCart(usercart);
System.out.println("AFTER ADD::usercart="+usercart.id+" has :"+usercart.cartItems.size()+" items");
assertFalse(usercart.cartItems.size()==0);//why does this fail?
}
private Response addItemsToCart(ShopCart cart) {
Product pdt = Product.find("byIsbn","654-0451160522").first();
assertNotNull(pdt);
System.out.println("addItemsToCart():BEFORE ADD cart="+cart.id+" has="+cart.cartItems.size());
Map<String,String> addtocartParams = new HashMap<String,String>();
addtocartParams.put("cartId", cart.id.toString());
addtocartParams.put("quantity", "2");
String addtocarturl = "/items/addtocart/"+pdt.id.toString();
Response response = POST(addtocarturl,addtocartParams);
System.out.println("addItemsToCart():AFTER ADD cart="+cart.id+" has="+cart.cartItems.size());
return response;
}
The console output I get is
BEFORE ADD::usercart=48 has :0 items
addItemsToCart():BEFORE ADD cart=48 has=0
Controller::addItemToCart()::cart id=48 has=1 items
addItemsToCart():AFTER ADD cart=48 has=0
AFTER ADD::usercart=48 has :0 items
Here, in the controller method, the cart instance (of id=48) has 1 item after it is saved to db.But in the test method ,the cart instance of same id has 0 content.
I commented out the assertFalse method and retrieved the cart from db using the cartId.Even then the cart of same id has 0 content.I can't understand why this is happening..can anyone shed some light?
//test method body ..modified
ShopCart cart = ShopCart.findById(usercart.id);
System.out.println("AFTER ADD::cart="+cart.id+" has :"+cart.cartItems.size()+" items");
assertFalse(cart.cartItems.size()==0);//why does this fail?
It fails because the cart instance used by your test method and the cart instance used by the addItemToCart method are different. Each transaction has its own instance of the entity. And JPA doesn't automagically refresh an entity when some other transaction updates the row mapped by this entity.
You should reload the cart from the database after addItemsToCart has been called to check if something has been added to the cart in database.
I am a slave to object-oriented thinking, so what I'm wondering is, have you thought about making addItemsToCart() a method of your ShopCart class? I'm envisioning something like:
...
ShopCart usercart = new ShopCart(user);
usercart.addItemsToCart(pdt);
usercart.save();
String addtocarturl = "/items/addtocart/"+pdt.id.toString();
Response response = POST(addtocarturl,addtocartParams);
return response;
It's just easier for me to think about making (or retrieving) a ShopCart object, modifying it, and putting it in the database. That's how I would avoid this.
I had the same issue and adding JPA.em().clear() in my test before I get the model from the database solved this issue for me.

Transaction issue in java with hibernate - latest entries not pulled from database

I'm having what seems to be a transactional issue in my application. I'm using Java 1.6 and Hibernate 3.2.5.
My application runs a monthly process where it creates billing entries for a every user in the database based on their monthly activity. These billing entries are then used to create Monthly Bill object. The process is:
Get users who have activity in the past month
Create the relevant billing entries for each user
Get the set of billing entries that we've just created
Create a Monthly Bill based on these entries
Everything works fine until Step 3 above. The Billing Entries are correctly created (I can see them in the database if I add a breakpoint after the Billing Entry creation method), but they are not pulled out of the database. As a result, an incorrect Monthly Bill is generated.
If I run the code again (without clearing out the database), new Billing Entries are created and Step 3 pulls out the entries created in the first run (but not the second run). This, to me, is very confusing.
My code looks like the following:
for (User user : usersWithActivities) {
createBillingEntriesForUser(user.getId());
userBillingEntries = getLastMonthsBillingEntriesForUser(user.getId());
createXMLBillForUser(user.getId(), userBillingEntries);
}
The methods called look like the following:
#Transactional
public void createBillingEntriesForUser(Long id) {
UserManager userManager = ManagerFactory.getUserManager();
User user = userManager.getUser(id);
List<AccountEvent> events = getLastMonthsAccountEventsForUser(id);
BillingEntry entry = new BillingEntry();
if (null != events) {
for (AccountEvent event : events) {
if (event.getEventType().equals(EventType.ENABLE)) {
Calendar cal = Calendar.getInstance();
Date eventDate = event.getTimestamp();
cal.setTime(eventDate);
double startDate = cal.get(Calendar.DATE);
double numOfDaysInMonth = cal.getActualMaximum(Calendar.DAY_OF_MONTH);
double numberOfDaysInUse = numOfDaysInMonth - startDate;
double fractionToCharge = numberOfDaysInUse/numOfDaysInMonth;
BigDecimal amount = BigDecimal.valueOf(fractionToCharge * Prices.MONTHLY_COST);
amount.scale();
entry.setAmount(amount);
entry.setUser(user);
entry.setTimestamp(eventDate);
userManager.saveOrUpdate(entry);
}
}
}
}
#Transactional
public Collection<BillingEntry> getLastMonthsBillingEntriesForUser(Long id) {
if (log.isDebugEnabled())
log.debug("Getting all the billing entries for last month for user with ID " + id);
//String queryString = "select billingEntry from BillingEntry as billingEntry where billingEntry>=:firstOfLastMonth and billingEntry.timestamp<:firstOfCurrentMonth and billingEntry.user=:user";
String queryString = "select be from BillingEntry as be join be.user as user where user.id=:id and be.timestamp>=:firstOfLastMonth and be.timestamp<:firstOfCurrentMonth";
//This parameter will be the start of the last month ie. start of billing cycle
SearchParameter firstOfLastMonth = new SearchParameter();
firstOfLastMonth.setTemporalType(TemporalType.DATE);
//this parameter holds the start of the CURRENT month - ie. end of billing cycle
SearchParameter firstOfCurrentMonth = new SearchParameter();
firstOfCurrentMonth.setTemporalType(TemporalType.DATE);
Query query = super.entityManager.createQuery(queryString);
query.setParameter("firstOfCurrentMonth", getFirstOfCurrentMonth());
query.setParameter("firstOfLastMonth", getFirstOfLastMonth());
query.setParameter("id", id);
List<BillingEntry> entries = query.getResultList();
return entries;
}
public MonthlyBill createXMLBillForUser(Long id, Collection<BillingEntry> billingEntries) {
BillingHistoryManager manager = ManagerFactory.getBillingHistoryManager();
UserManager userManager = ManagerFactory.getUserManager();
MonthlyBill mb = new MonthlyBill();
User user = userManager.getUser(id);
mb.setUser(user);
mb.setTimestamp(new Date());
Set<BillingEntry> entries = new HashSet<BillingEntry>();
entries.addAll(billingEntries);
String xml = createXmlForMonthlyBill(user, entries);
mb.setXmlBill(xml);
mb.setBillingEntries(entries);
MonthlyBill bill = (MonthlyBill) manager.saveOrUpdate(mb);
return bill;
}
Help with this issue would be greatly appreciated as its been wracking my brain for weeks now!
Thanks in advance,
Gearoid.
Is your top method also transactional ? If yes most of the time i've encountered that kind of problem, it was a flush that was not done at the right time by hibernate.
Try to add a call to session.flush() at the beginning of the getLastMonthsBillingEntriesForUser method, see if it address your problem.
Call session.flush() AND session.close() before getLastMonthsBillingEntriesForUser gets called.
Please correct my assumptions if they are not correct...
As far as I can tell, the relationship between entry and user is a many to one.
So why is your query doing a "one to many" type join? You should rather make your query:
select be from BillingEntry as be where be.user=:user and be.timestamp >= :firstOfLastMonth and be.timestamp < :firstOfCurrentMonth
And then pass in the User object, not the user id. This query will be a little lighter in that it will not have to fetch the details for the user. i.e. not have to do a select on user.
Unfortunately this is probably not causing your problem, but it's worth fixing nevertheless.
Move the declaration of BillingEntry entry = new BillingEntry(); to within the for loop. That code looks like it's updating one entry over and over again.
I'm guessing here, but what you've coded goes against what I think I know about java persistence and hibernate.
Are you certain that those entries are being persisted properly? In my mind, what is happening is that a new BillingEntry is being created, it is then persisted. At this point the next iteration of the loop simply changes the values of an entry and calls merge. It doesn't look like you're doing anything to create a new BillingEntry after the first time, thus no new id's are generated which is why you can't retrieve them later.
That being said, I'm not convinced the timing of the flush isn't a culprit here either, so I'll wait with bated breathe for the downvotes.

Categories

Resources