2
votes

I want to call an ArrayList stored in applicationScope from another class

I have a class, something like this that stores a bounch of data in a public variable names AL_data, the method getAllData just store the data in AL_data

public class Application implements Serializable{

    private static final long serialVersionUID = 1L;
    public ArrayList<District> AL_data;

    public Application(){
        try {
            getAllData();
        } catch (NotesException e) {
            e.printStackTrace();
        }
    }
}

And I have set the class as a managed bean in faces-config using applicationScope

<managed-bean>
    <managed-bean-name>App</managed-bean-name>
    <managed-bean-class>com.utils.Application</managed-bean-class>
    <managed-bean-scope>application</managed-bean-scope>
</managed-bean>

I also have another class that I want to use to read the applications scope

public class actions {

    private static Map<String, Object> applicationScope() {
        FacesContext context = FacesContext.getCurrentInstance();
        return (Map<String, Object>) context.getApplication().getVariableResolver().resolveVariable(context,"applicationScope");
    }

    public Vector<String> getDataForCurrentUser() {

        try {

            // how do I access the AL_data arraylist stored in applicationscope
    // ArrayList m = (ArrayList) this.applicationScope();


        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

and I have set this class as a manages bean using sessionScope.

<managed-bean>
    <managed-bean-name>Actions</managed-bean-name>
    <managed-bean-class>com.utils.actions</managed-bean-class>
    <managed-bean-scope>session</managed-bean-scope>
</managed-bean>

I would like to know how I can call the application scope class and access it's public properties, or how I can return my ArrayList.

thanks

Thomas

2

2 Answers

3
votes

Add a public method to your application scoped bean that other Java classes can use to access the instance of that bean:

public static Application get() {
    FacesContext context = FacesContext.getCurrentInstance();
    return (Application) context.getApplication().getVariableResolver().resolveVariable("App");
}

You can then use that method to get to the instance of the application scoped bean from your Actions class and then access the methods and variables of that bean:

public class actions {

public Vector<String> getDataForCurrentUser() {
        // Access the AL_data arraylist stored in the App application scoped bean
        ArrayList<District>  m = Application.get().AL_data;
}
3
votes

As long as the scope rules allow for it the best approach is to let the framework handle the injection of properties and beans into other beans.

Since you need an app-scoped bean inside of a session-scoped bean you can simply define the injection as follows:

<managed-bean>
    <managed-bean-name>Actions</managed-bean-name>
    <managed-bean-class>com.utils.actions</managed-bean-class>
    <managed-bean-scope>session</managed-bean-scope>
    <managed-property>
      <property-name>application</property-name>
      <value>#{App}</value>
    </managed-property>
</managed-bean>

To accept the injection of the property within you Actions bean define a public method as follows:

public class actions implements Serializable {

    private Application app;

    public void setApplication(Application app) {
        this.app = app;
    }

}

In this way you can have hold of the app bean anywhere you need it in the class without having to resolve it time and again whenever you need it. You might also decide that having the app bean referenced is too much and you just want the data. At that point you just need to tweak the faces-config.xml and the receiving method accordingly to get just that.

    <managed-property>
      <property-name>allData</property-name>
      <value>#{App.allData}</value>
    </managed-property>
public class actions implements Serializable {

    private static final long serialVersionUID = 1L;

    private ArrayList<District> allData;

    public void setAllData(ArrayList<District> allData) {
        this.allData = allData;
    }

}

Now, two pieces of advice.

  1. I would discourage you from initializing the bean's data within the constructor. Beans are meant to be lazily used and therefore the data should be lazily loaded. If you need to preload data the constructor is not the right place. Unfortunately we are stuck with undead XPages so there's no better help than fixing the problem by checking whether the variable in question has been set or not. That means taking an approach similar to this:
public class Application implements Serializable {

    private static final long serialVersionUID = 1L;

    private ArrayList<District> allData;

    //public Application(){
    //    try {
    //        getAllData();
    //    } catch (NotesException e) {
    //        e.printStackTrace();
    //    }
    //}

    public ArrayList<District> getAllData() {
        if (allData == null) {
           try {
                allData = // your logic result
            } catch (NotesException e) {
                throw new FacesException(e);
            }
        }

        return allData;
    }

}
  1. I would encourage you to use well established naming conventions that say that property names should start with lowercase characters (app instead of App) and class names with upper case character (com.utils.Actions instead of com.utils.actions)