Monday, October 23, 2017

Grails Link Generator | Generate Links Outside Controllers or Tag Libraries | Using grailsLinkGenerator to generate link | Custom Link Generator

Grails Link Generator | Generate Links Outside Controllers or Tag Libraries | Using grailsLinkGenerator to generate link | Custom Link Generator

It's easy, just need to follow below steps:
First create a properties file named "application.properties" under web-app/WEB-INF as follows:


configs.serverURL=http://localhost:8033/custom-link-generator-bean


Now create a Groovy file named "ConfigurationProperties.groovy" with below contents:


package com.link

import grails.util.Environment

/**
 * Created by pritom on 23/10/2017.
 */
class ConfigurationProperties {
    public static final String DEV_DIR = "web-app/WEB-INF"
    private static Properties ppt

    static getProperty(String name, def defaultV = null) {
        if (ppt == null) {
            ppt = new Properties()
            loadProperties("application.properties")
        }

        def result = ppt.getProperty(name, defaultV?.toString())
        return result == "" ? defaultV : result
    }

    static loadProperties(String fileName) {
        URL url = ConfigurationProperties.class.getResource("ConfigurationProperties.class")
        String thisPath = url.getPath(), path
        if(Environment.current == Environment.DEVELOPMENT || Environment.current == Environment.TEST) {
            path = "file://" + thisPath.substring(0, thisPath.lastIndexOf("target")) + "${DEV_DIR}/${fileName}"
        }
        else {
            path = "file://" + thisPath.substring(0, thisPath.lastIndexOf("classes")) + fileName
        }

        new File(path.toURI()).getCanonicalFile().withInputStream { InputStream stream ->
            ppt.load(stream)
        }
    }
}


Now create a Groovy file named "MyLinkGenerator.groovy" with below contents:


package com.link

import org.codehaus.groovy.grails.web.mapping.DefaultLinkGenerator
import org.codehaus.groovy.grails.web.mapping.LinkGenerator
/**
 * Created by pritom on 23/10/2017.
 */
class MyLinkGenerator extends DefaultLinkGenerator implements LinkGenerator {
    MyLinkGenerator(String serverBaseURL, String contextPath) {
        super(serverBaseURL, contextPath)
    }

    MyLinkGenerator(String serverBaseURL) {
        super(serverBaseURL)
    }

    String makeServerURL() {
        return ConfigurationProperties.getProperty("configs.serverURL")
    }

    String link(Map attrs, String encoding = 'UTF-8') {
        String cp = super.getContextPath()
        String url = super.link(attrs, encoding)
        if (cp) {
            if (cp != null && url.startsWith(cp)) url = url.substring(cp.length())
            if (url.startsWith("/")) url = url.substring(1)
            return makeServerURL() + "/" + url
        }
        return url
    }
}


Now add below lines to BootStrap.groovy


import com.link.MyLinkGenerator
import grails.spring.BeanBuilder
import org.codehaus.groovy.grails.commons.GrailsApplication

import javax.servlet.ServletContext

class BootStrap {
    ServletContext servletContext
    GrailsApplication grailsApplication

    def init = { servletContext ->
        grailsApplication.mainContext.removeBeanDefinition("grailsLinkGenerator")
        BeanBuilder bb = new BeanBuilder()
        bb.beans {
            grailsLinkGenerator(MyLinkGenerator, null)
        }
        bb.registerBeans(grailsApplication.mainContext)
    }

    def destroy = {

    }
}


And create another Groovy file named "AsyncManager.groovy" with below contents to check it in thread:


package com.link

/**
 * Created by pritom on 23/10/2017.
 */
class AsyncManager {
    static void run(Closure closure) {
        TimerTask task = new TimerTask() {
            @Override
            void run() {
                try {
                    closure.call()
                }
                catch (Exception e) {
                    e.printStackTrace()
                }
            }
        }
        new Timer().schedule(task, 1000L)
    }
}


And finally add a controller with below contents:


package com.link

class CustomLinkController {
    def grailsLinkGenerator

    def index() {
        println "In-request"
        println "Generator=${grailsLinkGenerator.class}"
        println "Base-url=${grailsLinkGenerator.serverBaseURL}"
        println "Controller-url=${grailsLinkGenerator.link(controller: "customLink", action: "index", params: [id: 2, name: "Pritom Kumar"])}"

        AsyncManager.run {
            println ""
            println "In-non-request"
            println "Generator=${grailsLinkGenerator.class}"
            println "Base-url=${grailsLinkGenerator.serverBaseURL}"
            println "Controller-url=${grailsLinkGenerator.link(controller: "customLink", action: "index", params: [id: 2, name: "Pritom Kumar"])}"
        }
        render ""
    }
}


Output would be as follows:


--------------WITHOUT CUSTOM LINK GENERATOR-----------------------
In-request
Generator=class asset.pipeline.grails.CachingLinkGenerator
Base-url=http://localhost:8033/custom-link-generator-bean
Controller-url=/custom-link-generator-bean/customLink/index/2?name=Pritom+Kumar

In-non-request
Generator=class asset.pipeline.grails.CachingLinkGenerator
Base-url=http://localhost:8080/custom-link-generator-bean
Controller-url=/custom-link-generator-bean/customLink/index/2?name=Pritom+Kumar


--------------WITH CUSTOM LINK GENERATOR-----------------------
In-request
Generator=class com.link.MyLinkGenerator
Base-url=http://localhost:8033/custom-link-generator-bean
Controller-url=http://localhost:8033/custom-link-generator-bean/customLink/index/2?name=Pritom+Kumar

In-non-request
Generator=class com.link.MyLinkGenerator
Base-url=http://localhost:8033/custom-link-generator-bean
Controller-url=http://localhost:8033/custom-link-generator-bean/customLink/index/2?name=Pritom+Kumar




Friday, October 20, 2017

MySQL SUM function in multiple joins | MySQL JOIN with multiple tables and SUMS | Using SUM with multiple joins in mysql

MySQL SUM function in multiple joins | MySQL JOIN with multiple tables and SUMS | Using SUM with multiple joins in mysql


SELECT x1.id,SUM(x1.amount) as fake_total,COUNT(x1.id) as count,
(SELECT SUM(amount) FROM t1 WHERE t1.id=x1.id) as actual_total
FROM t1 x1 LEFT JOIN t2 x2 on x2.t1=x1.id
GROUP BY x1.id
ORDER BY x1.id asc

If you on "EXPLAIN" mode then you will get the below data:


EXPLAIN
SELECT x1.id,SUM(x1.amount) as fake_total,COUNT(x1.id) as count,
(SELECT SUM(amount) FROM t1 WHERE t1.id=x1.id) as actual_total
FROM t1 x1 LEFT JOIN t2 x2 on x2.t1=x1.id
GROUP BY x1.id
ORDER BY x1.id asc




Actually it will not take too much time to execute

Wednesday, October 18, 2017

Hooking into GORM events | Hooking into GORM custom event listener from plugin in Grails | Grails Custom Gorm Event Listener

Hooking into GORM events | Hooking into GORM custom event listener from plugin in Grails | Grails Custom Gorm Event Listener

At first configure your datasource.groovy to connect with your desired database as below:


dataSource {
    pooled = true
    jmxExport = true
    driverClassName = "org.h2.Driver"
    username = "sa"
    password = ""
}
hibernate {
    cache.use_second_level_cache = true
    cache.use_query_cache = true
    cache.region.factory_class = 'net.sf.ehcache.hibernate.EhCacheRegionFactory'
    cache.provider_class = 'net.sf.ehcache.hibernate.EhCacheProvider'
    format_sql = false
    use_sql_comments = false
}

// environment specific settings
environments {
    development {
        dataSource {
            pooled = true
            url = "jdbc:mysql://localhost/my_db?useUnicode=yes&characterEncoding=UTF-8"
            driverClassName = "com.mysql.jdbc.Driver"
            username = "root"
            password = ""
            dialect = "org.hibernate.dialect.MySQL5InnoDBDialect"
            dbCreate = "update"
            properties {
                jmxEnabled = true
                initialSize = 5
                maxActive = 50
                minIdle = 5
                maxIdle = 25
                maxWait = 10000
                maxAge = 10 * 60000
                timeBetweenEvictionRunsMillis = 5000
                minEvictableIdleTimeMillis = 60000
                validationQuery = "SELECT 1"
                validationQueryTimeout = 3
                validationInterval = 15000
                testOnBorrow = true
                testWhileIdle = true
                testOnReturn = false
                jdbcInterceptors = "ConnectionState"
                defaultTransactionIsolation = java.sql.Connection.TRANSACTION_READ_COMMITTED
            }
            logSql = true
            loggingSql = true
        }
    }
    test {
        dataSource {
            
        }
    }
    production {
        dataSource {
            
        }
    }
}


Now add "runtime 'mysql:mysql-connector-java:5.1.29'" to your BiuldConfig.groovy file under "dependencies" section if you used MySQL.
Now create controller like below:

package com.custom_gorm_event_listener

class HomeController {
    def index() {
        println("Tracking-post-load-function")
        println(Home.list())
        println("")
        println("")
        println("Tracking-post-update-function")
        Home.last().departmentName = "Department-${System.currentTimeMillis()}".toString()
        render ""
    }
}

And as well as a Domain class as below:

package com.custom_gorm_event_listener

class Home {
    Long id
    String name
    String roll
    String departmentName

    static constraints = {
        departmentName nullable: true
    }
}

This is the most important step, need to create and gorm event listener class as below:

package com.custom_gorm_event_listener

import grails.util.Holders
import org.codehaus.groovy.grails.orm.hibernate.EventTriggeringInterceptor
import org.codehaus.groovy.grails.orm.hibernate.HibernateDatastore
import org.grails.datastore.mapping.core.Datastore
import org.grails.datastore.mapping.engine.event.AbstractPersistenceEvent
import org.grails.datastore.mapping.engine.event.ValidationEvent
import org.hibernate.HibernateException
import org.hibernate.event.spi.AbstractPreDatabaseOperationEvent
import org.hibernate.event.spi.PostDeleteEvent
import org.hibernate.event.spi.PostInsertEvent
import org.hibernate.event.spi.PostLoadEvent
import org.hibernate.event.spi.PostUpdateEvent
import org.hibernate.event.spi.PreDeleteEvent
import org.hibernate.event.spi.PreInsertEvent
import org.hibernate.event.spi.PreLoadEvent
import org.hibernate.event.spi.PreUpdateEvent
import org.hibernate.event.spi.SaveOrUpdateEvent

/**
 * Created by pritom on 18/10/2017.
 */
class GormEventListener extends EventTriggeringInterceptor {
    GormEventListener() {
        this((HibernateDatastore) Holders.applicationContext.getBean(Datastore), new ConfigObject())
    }

    GormEventListener(HibernateDatastore datastore, ConfigObject co) {
        super(datastore, co)
    }

    protected void onPersistenceEvent(AbstractPersistenceEvent event) {
        super.onPersistenceEvent(event)
    }

    private void updateState(AbstractPreDatabaseOperationEvent event) {
        Object[] newState = event.persister.getPropertyValuesToInsert(event.entity, null, event.session)
        Object[] oldState = event.state
        newState.eachWithIndex { m, i ->
            oldState[i] = m
        }
    }

    boolean onPreInsert(PreInsertEvent event) {
        updateState(event)
        return false
    }

    void onPostInsert(PostInsertEvent event) {
        println("onPostInsert::${event.entity}")
    }

    boolean onPreUpdate(PreUpdateEvent event) {
        updateState(event)
        return false
    }

    void onPostUpdate(PostUpdateEvent event) {
        println("onPostUpdate::${event.entity}")
    }

    boolean onPreDelete(PreDeleteEvent event) {
        return false
    }

    void onPostDelete(PostDeleteEvent event) {
        println("onPostDelete::${event.entity}")
    }

    void onPreLoad(PreLoadEvent event) {

    }

    void onPostLoad(PostLoadEvent event) {
        println("onPostLoad::${event.entity}")
    }

    void onSaveOrUpdate(SaveOrUpdateEvent event) throws HibernateException {
        println("onSaveOrUpdate::${event.entity}")
    }

    void onValidate(ValidationEvent event) {

    }
}

And finally need to hook our custom gorm event listener to gorm event, to do so we have to add some functionalities to BootStrap.groovy as below:

import com.custom_gorm_event_listener.GormEventListener
import org.codehaus.groovy.grails.commons.GrailsApplication
import org.springframework.context.event.AbstractApplicationEventMulticaster
import org.springframework.context.support.AbstractApplicationContext

class BootStrap {
    GrailsApplication grailsApplication

    def init = { servletContext ->
        addGormListener()
    }

    def destroy = {

    }

    void addGormListener() {
        AbstractApplicationContext context = grailsApplication.mainContext
        AbstractApplicationEventMulticaster multicaster = context.applicationEventMulticaster
        List listeners = multicaster.applicationListeners
        multicaster.removeAllListeners()
        /* Placing our listener at first */
        multicaster.addApplicationListener(new GormEventListener())
        listeners.each {
            multicaster.addApplicationListener(it)
        }
    }
}

We are finished, if we run our project we can track when an instance create, update or read through our listener:

Tracking-post-load-function
Hibernate: select this_.id as id1_0_0_, this_.version as version2_0_0_, this_.department_name as departme3_0_0_, this_.name as name4_0_0_, this_.roll as roll5_0_0_ from home this_
onPostLoad::com.custom_gorm_event_listener.Home : 53
onPostLoad::com.custom_gorm_event_listener.Home : 54
onPostLoad::com.custom_gorm_event_listener.Home : 55
[com.custom_gorm_event_listener.Home : 53, com.custom_gorm_event_listener.Home : 54, com.custom_gorm_event_listener.Home : 55]


Tracking-post-update-function
Hibernate: select this_.id as id1_0_0_, this_.version as version2_0_0_, this_.department_name as departme3_0_0_, this_.name as name4_0_0_, this_.roll as roll5_0_0_ from home this_ order by this_.id desc limit ?
Hibernate: update home set version=?, department_name=?, name=?, roll=? where id=? and version=?
onPostUpdate::com.custom_gorm_event_listener.Home : 55




Grails Bind Function | Method For Groovy Page View

Grails Bind Function | Method For Groovy Page View

Have to extend metaclass as below:


import org.codehaus.groovy.grails.web.pages.GroovyPage

GroovyPage.metaClass.with {
    xor = {
        "XOR-VALUE"
    }
    isTrue = { Map attrs = null ->
        println(attrs)
        return true
    }
}

And then you can use function/method in gsp page as below:


<h1>${xor()} ${isTrue(param1: 'value1', params2: 'value2') ? 'IS-TRUE' : 'IS-FALSE'}</h1>
<-- --="">

And output is as below:

XOR-VALUE IS-TRUE


Tuesday, October 17, 2017

Grails How to change logging level in runtime | Grails Set Log Level for Grails

Grails How to change logging level in runtime | Grails Set Log Level for Grails

Need to create a util class at first as below:


package com.log4j

import grails.util.Holders
import org.apache.log4j.Category
import org.apache.log4j.Level
import org.apache.log4j.Logger

/**
 * Created by pritom on 17/10/2017.
 */
class UtilsBase {
    protected static Logger log

    static void setLogLevel() {
        Level level = Holders.config?.myconfig?.log4j?.logLevel ?: Level.ERROR
        println("SETTING-LOG-LEVEL=${level}")
        Enumeration allLoggers = log.getLoggerRepository().getCurrentCategories()
        log.setLevel(level)
        while (allLoggers.hasMoreElements()) {
            Category category = (Category) allLoggers.nextElement()
            category.setLevel(level)
        }
    }

    static {
        println("Log-enabled-for-${this.class.simpleName}")
        log = Logger.getLogger(this.class)
    }
}

Need to do something in Config.groovy as below:


myconfig {
    log4j {
        /* Here you can define your LOG level */
        logLevel = Level.INFO
    }
}

// log4j configuration
// log4j configuration
log4j.main = {
    def pattern = new PatternLayout("%d{yyyy-MM-dd//HH:mm:ss.SSS} [%t] %x %-5p %c{2} - %m%n")

    appenders {
        console name: "stdout", layout: pattern
    }

    error   'org.codehaus.groovy.grails.web.servlet',        // controllers
            'org.codehaus.groovy.grails.web.pages',          // GSP
            'org.codehaus.groovy.grails.web.sitemesh',       // layouts
            'org.codehaus.groovy.grails.web.mapping.filter', // URL mapping
            'org.codehaus.groovy.grails.web.mapping',        // URL mapping
            'org.codehaus.groovy.grails.commons',            // core / classloading
            'org.codehaus.groovy.grails.plugins',            // plugins
            'org.codehaus.groovy.grails.orm.hibernate',      // hibernate integration
            'org.springframework',
            'org.hibernate',
            'net.sf.ehcache.hibernate',
            'com.log4j'

    debug   'com.log4j'

    warn    'org.springframework',
            'org.hibernate',
            'grails.plugins.springsecurity',
            'groovyx.net.http',
            'com.log4j'

    all     'grails.app'
}


Now you have to set log level fro BootStrap.goovy as below


import com.log4j.UtilsBase

class BootStrap {

    def init = { servletContext ->
        UtilsBase.setLogLevel()
    }
    def destroy = {

    }
}


And finally start loggin


package com.log4j

class Log4jController extends UtilsBase {
    def index() {
        log.info("Info")
        log.warn("Warn")
        log.error("Error")
        render ""
    }
}

Will output as below:


2017-10-17//16:16:15.512 [http-bio-8808-exec-4]  INFO  log4j.Log4jController - Info
2017-10-17//16:16:15.515 [http-bio-8808-exec-4]  WARN  log4j.Log4jController - Warn
2017-10-17//16:16:15.515 [http-bio-8808-exec-4]  ERROR log4j.Log4jController - Error




Monday, October 16, 2017

Grails 2.4 Traditional WebSocket Example | Grails Chat Application | Traditional Web Socket Chat Example

Grails 2.4 Traditional WebSocket Example | Grails Chat Application | Traditional Web Socket Chat Example

At first you need to create a configurator class under src/groovy as below:


import javax.websocket.HandshakeResponse
import javax.websocket.server.HandshakeRequest
import javax.websocket.server.ServerEndpointConfig
/**
 * Created by pritom on 5/10/2017.
 */
class TraditionalWebSocketConfigurator extends ServerEndpointConfig.Configurator {
    @Override
    public void modifyHandshake(ServerEndpointConfig config, HandshakeRequest request, HandshakeResponse response) {
        config.userProperties.put("MyKey", 100)
        config.userProperties.put("session", request.httpSession)
    }
}

Next you have to create a Handler class under scr/groovy as below:


import org.springframework.scheduling.TaskScheduler
import org.springframework.scheduling.concurrent.ConcurrentTaskScheduler

import javax.servlet.ServletContext
import javax.servlet.annotation.WebListener
import javax.websocket.*
import javax.websocket.server.ServerContainer
import javax.websocket.server.ServerEndpoint
/**
 * Created by pritom on 5/10/2017.
 */
@WebListener
@ServerEndpoint(value = "/WebSocket/traditional", configurator = TraditionalWebSocketConfigurator.class)
class TraditionalWebSocketHandler {
    private static List<Session> clients = []
    private static TaskScheduler clientRemoveScheduler = new ConcurrentTaskScheduler()

    @OnOpen
    public void handleOpen(Session userSession, EndpointConfig endpointConfig) {
        clients.add(userSession)
        println "WE HAVE OPEN SESSION #${userSession.id} " +
                "SESSION ${userSession.userProperties.session.id}"
    }

    @OnMessage
    public void handleMessage(String message, Session userSession) throws IOException {
        if (message) {
            println("SENDING TO ${clients.findAll { it.isOpen() }.size()}/${clients.size()} CLIENTS")
            message = "${userSession.id}: ${message}".toString()
            clients.findAll { it.isOpen() }.each { it.basicRemote.sendText(message) }
        }
    }

    @OnClose
    public void handeClose(Session userSession) throws SocketException {
        println "ONE CONNECTION CLOSED"
    }

    @OnError
    public void handleError(Throwable throwable) {
        println("HANDLE ERROR")
        throwable.printStackTrace()
    }

    static void init(final ServletContext servletContext) {
        final ServerContainer serverContainer = servletContext.getAttribute("javax.websocket.server.ServerContainer")
        serverContainer.addEndpoint(TraditionalWebSocketHandler)
        serverContainer.defaultMaxSessionIdleTimeout = 0

        clientRemoveScheduler.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                try {
                    clients.removeAll { !it.isOpen() }
                }
                catch (Exception ex) {

                }
            }
        }, 1000L * 10)
    }
}

Next step is to init Handler from BootStrap.groovy as below:


import com.socket.TraditionalWebSocketHandler
import org.codehaus.groovy.grails.commons.GrailsApplication

import javax.servlet.ServletContext

class BootStrap {
    ServletContext servletContext
    GrailsApplication grailsApplication

    def init = { servletContext ->
        TraditionalWebSocketHandler.init(servletContext)
    }

    def destroy = {

    }
}

You are already done, next step is to generate a view to show chat window:


class SocketController {
    def index() {
        session.name = "Pritom Kumar"
        render view: "index"
    }
}


<html>
<head>
    <asset:javascript src="jquery-2.1.3.js"/>
</head>

<body>

<table>
    <tr>
        <td>User Message</td>
        <td><input type="text" autofocus class="message" required/></td>
    </tr>
    <tr>
        <td></td>
        <td><input class="button" type="button" value="Send"/></td>
    </tr>
</table>

<div class="log_div"></div>

<script type="text/javascript">
    var socket = new WebSocket("ws://localhost:8807/socket-chat-application/WebSocket/traditional");
    socket.onopen = function () {
        socket.send('Hello');
    };
    socket.onmessage = function (message) {
        $(".log_div").prepend("<div>" + message.data + "</div>");
    };
    socket.onclose = function () {

    };
    socket.onerror = function () {

    };

    $(".button").click(function () {
        var value = $.trim($(".message").val());
        if (value.length > 0) {
            socket.send(value);
            $(".message").val("").focus();
        }
    });

    $(".message").keypress(function (e) {
        if (e.keyCode == 13) {
            $(".button").click();
        }
    });
</script>

</body>
</html>

And finally below is a screenshot of browser interaction:



Sunday, October 15, 2017

Grails - Register SessionListener as a Spring Bean

Grails - Register SessionListener as a Spring Bean

At first you have to create an listener of session as below:


package com.multidb.listener

import javax.servlet.http.HttpSessionEvent
import javax.servlet.http.HttpSessionListener
/**
 * Created by pritom on 15/10/2017.
 */
class HttpSessionServletListener implements HttpSessionListener {
    @Override
    void sessionCreated(HttpSessionEvent event) {
        println("HttpSessionServletListener:httpSessionCreated:${event.session}")
    }

    @Override
    void sessionDestroyed(HttpSessionEvent event) {
        println("HttpSessionServletListener:sessionDestroyed:${event.session}")
    }
}

Then you need to register in grails-app/conf/spring/resources.groovy as below:


import com.multidb.listener.HttpSessionServletListenererDataSource

beans = {
    httpSessionServletListener(HttpSessionServletListener) {

    }
}

And finally in Bootstrap.groovy


import com.multidb.listener.HttpSessionServletListener
import org.codehaus.groovy.grails.commons.GrailsApplication
import javax.servlet.ServletContext

class BootStrap {
    ServletContext servletContext
    GrailsApplication grailsApplication
    HttpSessionServletListener httpSessionServletListener

    def init = { servletContext ->
        servletContext.addListener(httpSessionServletListener)
    }

    def destroy = {

    }
}

So after an session is created or destroyed your custom listener will be notified.