Hello,
I have a stateless, session bean. All client code uses this bean to place
some entries in a history object (just a POJO to store some history
information).
I know that a statefull, session bean wouldn't solve the problem because
users will access this across sessions...
I implement this history object as a singleton, but every time a new bean is
created, it seems to get a new history object:
Does someone know what going on? I can attach the project if necessary.
thanks,
Daniel.
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
package com.localmatters.flexitext.ejb;
import com.localmatters.flexitext.support.HistoryTable;
import com.localmatters.flexitext.support.UserHistory;
import java.sql.Date;
import java.util.Set;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.ejb.Stateless;
import javax.ejb.Timeout;
import javax.ejb.Timer;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;
/**
* The history WS-EJB. The actual history is managed by
* {_at_link HistoryTable HistoryTable}, so all operations are delegated to it.
*
* @author Daniel Cavalcanti
*/
@Stateless()
@WebService()
public class HistoryBean implements HistoryRemote, HistoryLocal {
//
**********************************************************************
// Instance variables
//
**********************************************************************
/**
* All users' history.
*/
private HistoryTable historyTable;
//
**********************************************************************
// Constructors
//
**********************************************************************
/**
* Creates a new instance of HistoryBean.
*/
public HistoryBean() {
}
//
**********************************************************************
// Bean life-cycle methods
//
**********************************************************************
/**
* Gets reference to history table resource.
*/
@PostConstruct()
public void postConstruct() {
historyTable = historyTable.getInstance();
}
/**
* Periodic clean up method
*/
@Timeout()
public void clean(Timer timer) {
// TODO clean users temporary history
System.out.println("current time: " + new Date(
System.currentTimeMillis()));
}
//
**********************************************************************
// Bean methods
//
**********************************************************************
@WebMethod()
public Set<String> users() {
return historyTable.users();
}
@WebMethod()
public void clear() {
historyTable.clear();
}
@WebMethod()
public void clearOld(@WebParam() int age) {
historyTable.clear(age);
}
@WebMethod()
public void create(@WebParam() String user)
throws NullPointerException {
historyTable.create(user);
}
@WebMethod()
public UserHistory get(@WebParam() String user)
throws NullPointerException {
return historyTable.get(user);
}
@WebMethod()
public UserHistory remove(@WebParam() String user)
throws NullPointerException {
return historyTable.remove(user);
}
}
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
package com.localmatters.flexitext.support;
import java.io.Serializable;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
/**
* All users' history. This class is a thread-safe singleton.
*
* @author Daniel Cavalcanti
*/
public class HistoryTable implements Serializable {
//
**********************************************************************
// Singleton variable
//
**********************************************************************
/**
* The users' history singleton instance.
*/
private static HistoryTable singleton;
//
**********************************************************************
// Instance variables
//
**********************************************************************
/**
* The users' history.
*/
private Map<String, UserHistory> history;
//
**********************************************************************
// Constructor
//
**********************************************************************
/**
* Creates a new instance of HistoryTable.
*/
private HistoryTable() {
history = Collections.synchronizedMap(new TreeMap<String,
UserHistory>());
}
/**
* Returns the the users' history instance.
* HistoryTable factory method.
*
* @return The the users' history instance.
*/
public static HistoryTable getInstance() {
synchronized (HistoryTable.class) {
if (singleton == null)
singleton = new HistoryTable();
return singleton;
}
}
//
**********************************************************************
// History table methods
//
**********************************************************************
/**
* Returns a copy of the users set.
*
* @return A copy of the users set.
*/
public Set<String> users() {
return new TreeSet(history.keySet());
}
/**
* Clears the history table. This methods removes all user to
user-history
* entries.
*/
public void clear() {
synchronized (history) {
for (UserHistory userHistory : history.values())
userHistory.clear();
history.clear();
}
}
/**
* Clears the history older than age milliseconds. The user to
user-history
* entry is maintained. Only the actual history entries that are old are
* removed.
*
* @param age The age threshold in milliseconds.
*/
public void clear(int age) {
long threshold = System.currentTimeMillis() - age;
synchronized (history) {
for (UserHistory userHistory : history.values()) {
userHistory.clear(threshold);
}
}
}
/**
* Create a history entry for a user.
*
* @param user The user.
* @throws java.lang.NullPointerException see {_at_link
UserHistory#UserHistory() UserHistory}.
* @see UserHistory#UserHistory()
*/
public void create(String user)
throws NullPointerException {
history.put(user, new UserHistory());
}
/**
* Returns the user's history. If user does not have a history,
compulsively
* create one.
*
* @param user The user.
* @throws java.lang.NullPointerException If user is null.
* @return The user history.
*/
public UserHistory get(String user)
throws NullPointerException {
// attempt to get user's history
UserHistory entry = history.get(user);
// user does not have history -- create one
if (entry == null)
create(user);
// return user's history
return entry;
}
/**
* Removes a uer's history.
*
* @param user The user.
* @throws java.lang.NullPointerException If user is null.
* @return The user's history if it exists, null otherwise.
*/
public UserHistory remove(String user)
throws NullPointerException {
return history.remove(user);
}
}