Monday, 8 February 2016

The GRAILS WELT (WORLD) - PROFILE BASED BUILD

Welcome Friends!!!!!

It has really been quite sometime, since I wrote last.
Actually, after going a bit through GPars, I somehow felt to learn something new at the beginning of the year, then I suddenly it came to mind that why not GRAILS.

All I knew upto this point that GRAILS uses both Spring and Groovy and it is a Web Development Framework, so I jumped into it instantly started to explore it starting from the Very Beginner's Level with the help of its Official Documentation.

The First this which I saw at the Official Doc site, is that all I will be learning about GRAILS 3.0.x and at that time even I do not have any idea about the differences it has with the earlier version as I was not aware of them either, So every thing is very very new to me. All I can say after this timespan i.e. A Month and More that GRAILS is Awesome..

I am at an infancy level as far as GRAILS is concerned and I am gonna share my expereinces that I have during this time.
There may be cases where I can be wrong Or I may have adopted some approaches which are not appropriate, Please correct me in all those cases.

Now the differences that Grails 3 has with its previous version is well documented in its official site along with all the Migration Strategies, but the noteworthy features of Grails 3 that I have explored till now which has really enthralled me are the following:

1> The Spring Boot support along with GrailsAutoConfiguration providing a web.xml free applicatication
2> GRADLE Build System
3> The configuration in .yml file etc.
Now in this Post I will be discussing, Building Grails Project in Gradle for various Profiles (like DEV,UAT,STAGING,PRODUCTION etc.).
The Profile wise build that we can easily carry out with Maven, I initially find it quite difficult in configuring it with GRADLE, as I am fairly new to this promising Build EcoSystem may be one of the reasons.

However GRAILS CommandLine along with configuration file application.yml does satisfy my objective with ease, but all I wanted to do is:

1) Build the artifact from the command line using GRADLE, by passing the Profile as an argument for which I want to go for.
2) Deploy the artifact (As prepared in step 1) in server. (I have used Jetty 8.7.x here)
As I have said earlier, Grails with its grails <> run-app command does everything and makes the application up with embedded Tomcat. A Single Command For All so great isn't!!!!

The Approach that I have followed to satisfy my end is:

1> I have included another config file (.yml), where I have set the profile as passed from command line with Resource Filtering.
2> Then included the config file as Resources Config in the application so that it becomes a part of "GrailsApplication".
3> Then the value of application.profile key from the above config file is then set as java environment variable giving the name "grails.env", as GRAILS internally looks for this System Property during startup for configuring profile specific properties from application.yml which GRAILS does on its own, only in application.yml we need to configure properties in proper yml format for different profiles.
Let's traverse the code, I think then it can be bit more clear.
Start with build.gradle. I have added a Task named "deploy" which mostly does all the work along with "processResource" task.

GRADLE build system is so GREAT, that we can embed programming logic here. I have included an Exception Handling, and all this is due to "Groovy Grace".

Here is the code Excerpt.


apply plugin: "war"

task deploy (dependsOn: [makePretty,clean,war]){
    try{
    environment = env
    //println "The environment is $environment
    }
    catch(e)
    {
        println "The Error is: ${e.getMessage()}"
        if(e instanceof MissingPropertyException)
        {
            println "Please Execute Deploy TASK by passing parameter for Environment \n USAGE: gradle -Penv=<> deploy"
        }
        
        //throw new StopActionException(e.getMessage())

        55.times {
            print "*"
        }

        println ""

        println "No Build environment is provided, so we are setting it to UAT"
        environment = 'UAT'

        55.times {
            print "*"
        }

        println ""

    }

    doLast {
        println "Setting System Property"
        println "System Prop set to $environment"

        println "Deploying War......"
        copy{
            from "build/libs"
            into "C:/Users/MIC/Desktop/Cloud/jetty-distribution-8.1.17.v20150415/webapps"
            include "*.war"
        }
        println "Deployment Done......"
    }
}


processResources {
    filter ReplaceTokens, tokens: [
        "GRAILS.ENV": environment
    ]


}

task makePretty(type: Delete) {
   delete 'C:/Users/MIC/Desktop/Cloud/jetty-distribution-8.1.17.v20150415/webapps/HelloGrails.war'
 }
 
 war{
    sourceSets {
        main {
            resources {
                include '**/*.groovy'
                include '**/*.gsp'
                include '**/*.properties'
                include "**/application-profile.yml"
                include "**/application.yml"
                include "**/*.xml"
                //exclude 'application-staging.yml'
            }
        }
    }
	archiveName = "HelloGrails.war"
}


We have also included war plugin, so that we can alter war confuration during build with the help of war closure. In the closure we have indicated which of the files needs to be in the generated war.

The deploy task is dependent on other task dependsOn: [makePretty,clean,war], included that as well and finally the resource filter block which will replace the token with name "GRAILS.ENV" with the property value named "env" that we pass as parameter while executing the deploy task. If we do not pass any then the default profile is "UAT"

The command that is going to perform the build process is:

gradle -Penv=<<PROFILE_NAME>> deploy, For example: gradle -Penv=UAT deploy, or gradle -Penv=staging deploy or gradle -Penv=dev deploy etc. Now following the approach that we have discussed before, corresponding to Point 1, the Config file where we will record the profile from the command line so that we can configure the application during its startup time is:


application:
    profile: @GRAILS.ENV@

The file has been named as application-profile.yml and it as been included in the generated war artifact after the build has carried out from gradle as indicated in the war closure in build.gradle.

After successful build this configuration file would look like:

application:
    profile: UAT

Now corresponding to Point 2, we have included the above application-profile.yml file as part of the resource config with the help of the follwoing code in Application.groovy.



class Application extends GrailsAutoConfiguration implements EnvironmentAware {

   

    void setEnvironment(Environment environment) {

        PathMatchingResourcePatternResolver pathMatchingResourcePatternResolver = new PathMatchingResourcePatternResolver()
        Resource resourceConfig = pathMatchingResourcePatternResolver.findPathMatchingResources("classpath:application-*.yml")[0]

        YamlPropertiesFactoryBean ypfb = new YamlPropertiesFactoryBean()
        ypfb.setResources([resourceConfig] as Resource[])
        ypfb.afterPropertiesSet()

        Properties properties = ypfb.getObject()
        environment.propertySources.addFirst(new PropertiesPropertySource("environment.config", properties))

        def profile = environment.getProperty('application.profile')

        35.times {
            print "*"
        }

        println ""

        println "Starting Up for Profile is: $profile"

        35.times {
            print "*"
        }

        println ""

        System.setProperty("grails.env",profile)

    }

    static void main(String[] args) {

        println " *****  Going for StartUps......."
        GrailsApp.run(Application, args)
    }
}

We have made the Application.groovy to implement Spring EnvironmentAware, so that overriding the setEnvironment() method we add the above config file as a Property Resource with the help of Environment parameter.

Now, For Point 3, within the above method we accessed the property and set it as a System Parameter as:


System.setProperty("grails.env",profile)

After this property is set, Grails automatically access the property and configures its environment based on the value of the property (grails.env)

There are there know properties for Grails:

1) Development
2) Production
3) Test
Apart from all above properties, all other are conferred as CUSTOM.

This is in short about Profile Based Configuration in Grails with Gradle.

In my next post I will discuss Form submission in Grails with Collection Data (By Auto DataBinding with Command Objects)

Till next time Keep Sharing and Keep Contributing.........
View Subhankar Paul's profile on LinkedIn

No comments:

Post a Comment