views:

450

answers:

4

Is it possible to have objects stored in a data structure for the duration of an App Server's uptime? Basically I want an EJB that interfaces with this Data Structure, but does not require a full fledged database solution.

As an example I made this dummy animal object:

package com.test.entities;

public class Animal implements java.io.Serializable {

    private static final long serialVersionUID = 3621626745694501710L;
    private Integer id;
    private String animalName;

    public Integer getId() {
     // TODO Auto-generated method stub
     return id;
    } 
    public void setId(Integer id){
     this.id=id;
    }
    public String getAnimalName(){
     return animalName;

    }
    public void setAnimalName(String animalName){
     this.animalName=animalName;
    }
}

So here is the EJB Remote Interface:

package com.test.beans;

import java.util.Map;

import javax.ejb.Remote;

import com.test.entities.Animal;

@Remote
public interface MapBeanRemote {

    public void addAnimal(Animal a);

    public void removaAnimal(Integer id);

    public Animal getAnimalById(Integer id);

    Map<Integer, Animal> getAllAnimals();

}

Here is the Session Bean:

package com.test.beans;

import java.util.ConcurrentHashMap;
import java.util.Map;

import javax.annotation.PostConstruct;
import javax.ejb.Stateless;

import com.test.entities.Animal;

@Stateless(mappedName="ejb/MapBean")
public class MapBean implements MapBeanRemote{

    Map<Integer, Animal> animalStore;

    @PostConstruct
    public void initialize(){
     animalStore = new ConcurrentHashMap<Integer,Animal>();
    }

    @Override
    public void addAnimal(Animal a) {
     if(a.getId()!=null){
      animalStore.put(a.getId(), a);
     }
    }

    @Override
    public Animal getAnimalById(Integer id) {
     return animalStore.get(id);
    }

    @Override
    public void removaAnimal(Integer id) {
     animalStore.remove(id);

    }

    @Override
    public Map<Integer, Animal> getAllAnimals() {
     return animalStore;
    }

}

So basically I want any client who wants to manipulate the Animal Map to go through this EJB and have each client accessing the same exact Map of objects.

This example does not work good enough. After a while all of the animals are erased (I'm assuming when the EJB gets replaced from the bean pool) Could this somehow be injected as a resource?

A: 

Hi,

I think the best think would be to move the data structure out of the EJB completely and store it as a static data structure. You are probably correct in the fact that your objects are being erased because the EJB's are being pooled.

Note depending on how you implement access to the datastructure you many need to synchronize access to ensure thread safety.

If you want to maintain state inside your EJB then consider looking at stateful session beans. Also if you did want to see when the beans were being destroyed you could override the ejbremove method i forget the annotation for Java 5.

Karl

Karl
Thanks. Stateful Session beans are only for (as I understand it) maintaining state with a specific client, not for the whole app server.
Grasper
Yes your correct, sorry should have made that clear.
Karl
+1  A: 

This is a stateless session bean. As the name implies you should not hold any kind of state in such a bean. A EJB container may work with multiple instances of your bean to satisfy concurrent requests. How do you synchronize data of the Lists of all instances? I thing there is no way to do this.

Mainting such a List into a session bean, which provied the business logic, even violates the concept of the business layer in my opinion. You have to take care of transactions and concurrent write by your own.

Why dont you hold the List of animals on the client side? I thing this would be the better way.

Timo
I agree with violating the concept of business layer. That is why, ideally, I would be able to inject the Map as a resource of some sort. I need the ability to have the Map on the Server side because I am shoehorning a Java SE application into a Java EE context.
Grasper
An evil idea: Use a static class with a static Map that is used by all session beans and hope synchonization of the Map is well implemented and does not infuence the container doing his work.
Timo
+2  A: 

This can be accomplished by putting the Map in a Singleton and accessing this singleton from the beans. That way there is a single instance for all the EJB instances (since they share the same classloader). Different Session beans in different EAR's would not work though as they would each have their own classloader, but that doesn't appear to be your scenario.

Your existing usage of ConcurrentHashMap will sufficiently handle most of your cases but you still need synchronization around the addAnimal method since you need the map to be consistent between the two method calls.

Robin
+2  A: 

New EJB 3.1 spec provides new type of beans - Singleton beans - that are exactly what you need. The only implementation with partial support of EJB 3.1 I know of is Apache OpenEJB 3.1. It includes Singleton beans but I haven't used them yet.

grigory