Well I tried a similar exampe and it worked!! The only (minor)
difference is that the static Singleton is initialized during class
loading time in my example. The client created multiple threads and
called the sleepFor() method in Sless.
I am sure you might have already checked, but Can you print the hashcode
of the singleton and check if you get different instances?
--Mahesh
Daniel Cavalcanti wrote:
> 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);
> }
>
> }
>
/*
* Copyright 2002 Sun Microsystems, Inc. All rights reserved.
* SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*/
package com.sun.s1asdev.ejb.ejb30.hello.session;
import javax.ejb.Remote;
@Remote
public interface Sless
{
public String hello();
public String sleepFor(int sec);
}
/*
* Copyright 2002 Sun Microsystems, Inc. All rights reserved.
* SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*/
package com.sun.s1asdev.ejb.ejb30.hello.session;
import javax.ejb.Stateless;
import javax.annotation.PostConstruct;
@Stateless
public class SlessEJB implements Sless
{
private Singleton singleton;
@PostConstruct
public void init() {
singleton = Singleton.getInstance();
System.out.println("Singleton: " + singleton);
}
public String hello() {
System.out.println("In SlessEJB:hello()");
return "hello";
}
public String sleepFor(int sec) {
try {
Thread.currentThread().sleep(sec*1000);
} catch (Exception ex) {
}
return "sless: " + this + " => " + singleton;
}
}
package com.sun.s1asdev.ejb.ejb30.hello.session;
public class Singleton {
private static Singleton _singleton = new Singleton();
private Singleton() {
}
public static Singleton getInstance() {
return _singleton;
}
}