I am using filters to handle authentication and some other pre-condition checks for a Grails application. I've run into a situation where it'd be nice to ensure that filter A is always invoked before filter B |
If several filters are declared within one class, it's obvious that they'll be executed in the order that they were declared like below code block. |
package com.pkm class SecurityFilters { def filters = { filter1(controller:'*', action:'*') { before = { println("FILTER-1") } after = { Map model -> } afterView = { Exception e -> } } filter2(uri: "/**") { before = { println("FILTER-2") } after = { Map model -> } afterView = { Exception e -> } } } } |
Now what will happen if they would defined in different classes. Yes, there is a way around and that is dependsOn. You can define dependsOn on which filter it will depend on. Say I created another filter named Security2Filters and set my first filter named SecurityFilters to dependsOn. So SecirutyFilters will be execute before Security2Filters. |
package com.pkm class Security2Filters { def dependsOn=[SecurityFilters] def filters = { all(controller:'*', action:'*') { before = { println("FILTER-3") } after = { Map model -> } afterView = { Exception e -> } } } } |
Showing posts with label grails-2.4. Show all posts
Showing posts with label grails-2.4. Show all posts
Saturday, June 16, 2018
Grails on Groovy > Grails 2.X > How is the invocation sequence of Grails filters defined | Sequence of Filter Execution
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
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:
Subscribe to:
Posts (Atom)