Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Play Framework: merging multiple Global objects in multi-module project

I'm building a multi-module project using Play 2.3 and Java 8. Root application and each module have a Global object. But how we know Play uses only one Global object from root application.

Simplified folder structure:

/root
    /app
        Global.java
    /conf
        application.conf
    /subprojects
        /user
            /app
               UserGlobal.java
        /admin
            /app
               AdminGlobal.java

All Global classes placed in unnamed package.

I use such way for merging Global objects from subprojects:

1) Declared configuration variable in root application.conf

subprojects.with.globals="subprojectName1, subprojectName2, subprojectName3, ..."

2) Added private field and private method in root Global.java

private List<GlobalSettings> subprojectGlobals = new ArrayList<>();

private void LoadSubprojectGlobals(Application app)
    throws ClassNotFoundException, IllegalAccessException, InstantiationException
{
    String subprojectNames = 
        app.configuration().getString("subprojects.with.globals");
    if (!subprojectNames.isEmpty())
    {
        Class subprojectGlobalClass = null;
        for (String subprojectName : subprojectNames.split(","))
        {
            subprojectGlobalClass = Class.forName(
                WordUtils.capitalize(subprojectName.trim().toLowerCase()) +
                "Global"
            );
            subprojectGlobals.add(
                (GlobalSettings)subprojectGlobalClass.newInstance()
            );
        }
    }
}

3) Placed such code into onStart event handler in root Global.java

@Override
public void onStart(Application app)
{
    try
    {
        LoadSubprojectGlobals(app);
    }
    catch(Exception e)
    {
        new RuntimeException(e);
    }

    for(GlobalSettings subprojectGlobal: subprojectGlobals)
    {
        subprojectGlobal.onStart(app);
    }
}

Now if we add some new subproject we must edit subprojects.with.globals in root application.conf. And if we want to handle more global settings we need to override appropriate method in root Global.java.

It will be cool if we'll be able to determine all subproject names dynamically from java-code in root onStart. Is it possible? May be from root build.sbt or from Application object?

UPDATE

I changed my project applying @Mon Calamari's approach.

1) Removed configuration variable subprojects.with.globals from root application.conf.

2) Put all subproject Global classes into globals package:

/subprojects
    /user
        /app
            /globals
                UserGlobal.java
    /admin
        /app
            /globals
                AdminGlobal.java

3) Added configuration variable into all subproject conf files like a

application.global= globals.UserGlobal

4) Changed LoadSubprojectGlobals() implementation:

private void LoadSubprojectGlobals(Application app)
    throws ClassNotFoundException, IllegalAccessException, InstantiationException
{
    Reflections reflections = new Reflections("globals");
    Set<Class<? extends GlobalSettings>> subprojectGlobalClasses = 
        reflections.getSubTypesOf(GlobalSettings.class);

    for(Class subprojectGlobalClass : subprojectGlobalClasses)
    {
        subprojectGlobals.add(
            (GlobalSettings)subprojectGlobalClass.newInstance()
        );
    }
}

Now if we add some new subproject we must follow some conventions about adding Global class but we have no need to keep track sub projects list.

Thanks a lot.

like image 719
bovin.a Avatar asked Nov 09 '22 19:11

bovin.a


1 Answers

I am not sure how your modules/packages are arranged, but what if you use org.reflections to get all extensions of play.GlobalSettings class:

Reflections reflections = new Reflections("your.package");    
Set<Class<? extends GlobalSettings>> classes = reflections.getSubTypesOf(GlobalSettings.class)
like image 117
Mon Calamari Avatar answered Nov 15 '22 08:11

Mon Calamari