ejb@glassfish.java.net

Re: Singleton instance

From: Daniel Cavalcanti <dhcavalcanti_at_gmail.com>
Date: Fri, 4 Aug 2006 15:05:03 -0400

Hi Masesh,

I found out what the problem was, but I still can't figure out how to solve.
I forgot to copy a part of the code into what I had sent. Notice that I have
a method to execute on a timeout callback.
I declare a variable like this:

@Resource()
private TimerService timerService;

which I use to create a timer. Whenever I leave the timer related code in, I
get these errors. If I take that part out, which I had done to post the
message and that's why I forgot to copy in again, then all works fine. So it
seems that I'm doing something wrong with the timer.

Have you used them before?
Here is the code with the timer parts in:

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.ejb.TimerService;
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;

    /**
     * The timer service.
     */
    @Resource()
    private TimerService timerService;

    //
**********************************************************************
    // Constructors
    //
**********************************************************************

    /**
     * Creates a new instance of HistoryBean.
     */
    public HistoryBean() {
        // create history-table
        historyTable = historyTable.getInstance();

        // create timer for clean-up notifications
        timerService.createTimer(new Date(System.currentTimeMillis()), 5 *
60 * 1000, null);
    }

    //
**********************************************************************
    // Bean life-cycle methods
    //
**********************************************************************

    /**
     * Gets reference to history table resource.
     */
    @PostConstruct()
    public void postConstruct() {

        // create history-table
        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);
    }

}

An part of the exception due to this code:

[#|2006-08-04T14:39:
47.350-0400|INFO|sun-appserver-pe9.0|javax.enterprise.system.container.ejb|_ThreadID=16;_ThreadName=httpWorkerThread-8080-1;|EJB5070:
Exception creating stateless session bean : [{0}]
java.lang.IllegalStateException: EJB Timer method calls cannot be called in
this context
    at
com.sun.ejb.containers.SessionContextImpl.checkTimerServiceMethodAccess(
SessionContextImpl.java:324)
    at com.sun.ejb.containers.EJBTimerServiceWrapper.checkCallPermission(
EJBTimerServiceWrapper.java:237)
    at
com.sun.ejb.containers.EJBTimerServiceWrapper.checkCreateTimerCallPermission
(EJBTimerServiceWrapper.java:227)
    at com.sun.ejb.containers.EJBTimerServiceWrapper.createTimer(
EJBTimerServiceWrapper.java:160)
    at com.localmatters.flexitext.ejb.HistoryBean.postConstruct(
HistoryBean.java:68)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(
NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(
DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:585)
    at com.sun.ejb.containers.interceptors.BeanCallbackInterceptor$1.run(
InterceptorManager.java:601)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.ejb.containers.interceptors.BeanCallbackInterceptor.intercept
(InterceptorManager.java:595)
    at com.sun.ejb.containers.interceptors.CallbackChainImpl.invokeNext(
InterceptorManager.java:448)
    at com.sun.ejb.containers.interceptors.InterceptorManager.intercept(
InterceptorManager.java:204)
    at com.sun.ejb.containers.StatelessSessionContainer.createStatelessEJB(
StatelessSessionContainer.java:546)
    at com.sun.ejb.containers.StatelessSessionContainer.access$100(
StatelessSessionContainer.java:96)
    at
com.sun.ejb.containers.StatelessSessionContainer$SessionContextFactory.create
(StatelessSessionContainer.java:746)
    at com.sun.ejb.containers.util.pool.NonBlockingPool.getObject(
NonBlockingPool.java:186)
    at com.sun.ejb.containers.StatelessSessionContainer._getContext(
StatelessSessionContainer.java:469)
    at com.sun.ejb.containers.BaseContainer.getContext(BaseContainer.java
:1566)
    at com.sun.ejb.containers.BaseContainer.preInvoke(BaseContainer.java
:1148)
    at com.sun.ejb.containers.EJBLocalObjectInvocationHandler.invoke(
EJBLocalObjectInvocationHandler.java:182)
    at com.sun.ejb.containers.EJBLocalObjectInvocationHandlerDelegate.invoke
(EJBLocalObjectInvocationHandlerDelegate.java:71)
    at $Proxy83.get(Unknown Source)
    at com.localmatters.flexitext.servlet.StoreServlet.processRequest(
StoreServlet.java:44)
    at com.localmatters.flexitext.servlet.StoreServlet.doGet(
StoreServlet.java:77)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:707)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:820)
    at org.apache.catalina.core.ApplicationFilterChain.servletService(
ApplicationFilterChain.java:397)
    at org.apache.catalina.core.StandardWrapperValve.invoke(
StandardWrapperValve.java:278)
    at org.apache.catalina.core.StandardPipeline.doInvoke(
StandardPipeline.java:566)
    at org.apache.catalina.core.StandardPipeline.invoke(
StandardPipeline.java:536)
    at org.apache.catalina.core.StandardContextValve.invokeInternal(
StandardContextValve.java:240)
    at org.apache.catalina.core.StandardContextValve.invoke(
StandardContextValve.java:179)
    at org.apache.catalina.core.StandardPipeline.doInvoke(
StandardPipeline.java:566)
    at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:73)
    at org.apache.catalina.core.StandardHostValve.invoke(
StandardHostValve.java:182)
    at org.apache.catalina.core.StandardPipeline.doInvoke(
StandardPipeline.java:566)
    at com.sun.enterprise.web.VirtualServerPipeline.invoke(
VirtualServerPipeline.java:120)
    at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:939)
    at org.apache.catalina.core.StandardEngineValve.invoke(
StandardEngineValve.java:137)
    at org.apache.catalina.core.StandardPipeline.doInvoke(
StandardPipeline.java:566)
    at org.apache.catalina.core.StandardPipeline.invoke(
StandardPipeline.java:536)
    at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:939)
    at org.apache.coyote.tomcat5.CoyoteAdapter.service(CoyoteAdapter.java
:231)
    at com.sun.enterprise.web.connector.grizzly.ProcessorTask.invokeAdapter(
ProcessorTask.java:667)
    at
com.sun.enterprise.web.connector.grizzly.ProcessorTask.processNonBlocked(
ProcessorTask.java:574)
    at com.sun.enterprise.web.connector.grizzly.ProcessorTask.process(
ProcessorTask.java:844)
    at
com.sun.enterprise.web.connector.grizzly.ReadTask.executeProcessorTask(
ReadTask.java:287)
    at com.sun.enterprise.web.connector.grizzly.ReadTask.doTask(
ReadTask.java:212)
    at com.sun.enterprise.web.connector.grizzly.TaskBase.run(TaskBase.java
:252)
    at com.sun.enterprise.web.connector.grizzly.WorkerThread.run(
WorkerThread.java:75)
|#]

[#|2006-08-04T14:39:
47.353-0400|INFO|sun-appserver-pe9.0|javax.enterprise.system.container.ejb|_ThreadID=16;_ThreadName=httpWorkerThread-8080-1;HistoryBean;|EJB5018:
An exception was thrown during an ejb invocation on [HistoryBean]|#]




On 8/4/06, Mahesh.Kannan <Mahesh.Kannan_at_sun.com> wrote:
>
> 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;
> }
> }
>
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: ejb-unsubscribe_at_glassfish.dev.java.net
> For additional commands, e-mail: ejb-help_at_glassfish.dev.java.net
>
>