users@glassfish.java.net

JNDI ConcurrentHashMap resource

From: <glassfish_at_javadesktop.org>
Date: Thu, 18 Mar 2010 19:08:19 PDT

Hello. I'm trying to store a ConcurrentHashMap in JNDI for beans to read and update from, however it seems to be overwriting the ConcurrentHashMap with a new one when its referrenced by a second bean.

Firstly why am I going down this route? Well the beans may belong to different JVMs, so I ruled out using a singleton bean holding the ConcurrentHashMap. Also, since the objects that will be referenced in the ConcurrentHashMap aren't serializable (they're actually JMS queue objects), I can't write them to a database and get round the problem that way.

Okay, so I have the following test case:

In my bean package:

[b]demo/FirstBean.java[/b]:

[code]
package demo;

import java.util.concurrent.ConcurrentHashMap;
import javax.annotation.Resource;
import javax.ejb.Stateless;

@Stateless
public class FirstBean implements FirstRemote
{
        @Resource(mappedName="custom/map")
        private ConcurrentHashMap map;

        public void first()
        {
                System.out.println("Call to First");
                map.put("First", Integer.valueOf(1));
                System.out.println("map after inserting first = " + map);
        }
}
[/code]

[b]demo/FirstRemote.java[/b]:

[code]package demo;

import javax.ejb.Remote;

@Remote
public interface FirstRemote
{
        void first();
}[/code]

[b]demo/SecondBean.java[/b]:

[code]package demo;

import java.util.concurrent.ConcurrentHashMap;
import javax.annotation.Resource;
import javax.ejb.Stateless;

@Stateless
public class SecondBean implements SecondRemote
{
        @Resource(mappedName="custom/map")
        private ConcurrentHashMap map;

        public void second()
        {
                System.out.println("Call to Second");
                System.out.println("map = " + map);
        }
}[/code]
[b]demo/SecondRemote.java[/b]:

[code]package demo;

import javax.ejb.Remote;

@Remote
public interface SecondRemote
{
        void second();
}[/code]

In my app package:

[b]resourcedemo/Main.java[/b]:

[code]package resourcedemo;

import demo.FirstRemote;
import demo.SecondRemote;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.naming.InitialContext;
import javax.naming.NamingException;

public class Main
{
        private static InitialContext ctx = null;

        /**
         * @param args the command line arguments
         */
        public static void main(String[] args)
        {
                try
                {
                        FirstRemote first = (FirstRemote)getContext().lookup("ejb/FirstBean");
                        SecondRemote second = (SecondRemote)getContext().lookup("ejb/SecondBean");

                        first.first();
                        second.second();
                }
                catch (NamingException ex)
                {
                        Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
                }
        }

        private static InitialContext getContext()
        {
                if (ctx == null)
                {
                        Properties props = new Properties();
                        props.setProperty("java.naming.factory.initial", "com.sun.enterprise.naming.SerialInitContextFactory");
                        props.setProperty("java.naming.factory.url.pkgs", "com.sun.enterprise.naming");
                        props.setProperty("java.naming.factory.state", "com.sun.corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl");

                        props.setProperty("org.omg.CORBA.ORBInitialHost", "192.168.16.89");
                        props.setProperty("org.omg.CORBA.ORBInitialPort", "3791");
                        try
                        {
                                ctx = new InitialContext(props);
                        }
                        catch (NamingException ex)
                        {
                                Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
                        }
                }
                return ctx;
        }
}[/code]

In my custom glassfish library:

[b]demo/ConcurrentHashMapLibrary.java[/b]:

[code]package demo;

import java.util.Hashtable;
import java.util.concurrent.ConcurrentHashMap;
import javax.naming.Context;
import javax.naming.Name;
import javax.naming.spi.ObjectFactory;

public class ConcurrentHashMapFactory implements ObjectFactory
{
        public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable<?, ?> environment) throws Exception
        {
                System.out.println(">>> Creating and returning a new ConcurrentHashMap instance <<<");
                return new ConcurrentHashMap();
        }
}[/code]

So, when I run the app client, I see the following in the glassfish log:

[code]INFO: >>> Creating and returning a new ConcurrentHashMap instance <<<
INFO: Call to First
INFO: map after inserting first = {First=1}
INFO: >>> Creating and returning a new ConcurrentHashMap instance <<<
INFO: Call to Second
INFO: map = {}[/code]

So, the FirstBean causes Glassfish to create a ConcurrentHashMap, but when the second bean is called, instead of reusing the map, it creates a new instance.

I feel like I'm missing something fundamental, but what?
[Message sent by forum member 'antilochus']

http://forums.java.net/jive/thread.jspa?messageID=392664