Showing posts with label Grails. Show all posts
Showing posts with label Grails. Show all posts

Tuesday, October 4, 2022

How to use static content / resource files in app root directory in grails

In Grails latest version like 4 and 5, it provides static assets management mechanism more standard way. We can use different files under the corresponding folders.
All the images will go under the images directory, js files go under the javascripts directory and CSS goes under the stylesheets directory. These files will be accessed by the URL path start with "/assets/".
Now, what if you don't want to use this structure or need to use the root path for some static file content.
For this, grails provide another option to manage static resources. So, what you can do is create the /resources/public directory under /src/main/ and use static resources there.
For example, if you had a file under /src/main/resources/public/images/example.jpg path then you can access that file using https://example.com/static/images/example.jpg.
This means, your file can be accessed with "/static/" URL by default. If you want to access the file in the app root directory, setup the following configuration under application.groovy

grails.resources.pattern = '/**'
Now, for the above example the file can be accessed with https://example.com/images/example.jpg URL and if the file is in /public/ directory that file can be accessed with root path https://example.com/file.js

Thursday, September 29, 2022

Tracking of Stackoverflow Exception from Grails / Gradle Project - Caused by: java.lang.StackOverflowError: null

In many cases we may face Stackoverflow exception and in my many cases I didn't find the exact point where this exception occurred.
Then I start checked my debug output and found that from UrlMappingUtils.java class in package org.grails.web.mapping is the reason of StackoverflowException rather than throwing the main Exception.
This is because of handling of Exception is not handled properly.
Then I set a breakpoint inside method public static String forwardRequestForUrlMappingInfo and found the original Exception from there.

Add resources and config files to your JAR using Gradle Build for Grails Application

How do I add config files or any other resources into my jar using gradle?
How to include everything inside src/main/java to compile

I have a project. Inside the project I have few files like x.properties, x.csv and many more under src/main/webapp package, I used gradle to compile, I didn’t see src/main/webapp directory in my build folder.

How can I include everything to build? Because I need to include contents inside src/main/webapp directory to be include in my jar so that resources can be accessible by who will use my jar.
So first step is to tell compiler to include files in jar file using below code snippet -
Add below code snippet to build.gradle:

sourceSets {
    main {
        resources {
            srcDir "src/main/webapp"
            include "*.properties"
            include "*.csv"
            exclude "*.png"
            exclude "a1"
            exclude "a2"

            srcDir "src/main/webapp/a1"
            exclude "**/*.text"
            include "**/*.csv"

            srcDir "src/main/webapp/a2"
            include "**/*.html"
        }
    }
}
My project structure is like below:
And the files stored in the generated jar file as below:
Now the process to use the resources file into the project, add below configuration to build.gradle file (which project will use jar created above):

copy{
    from(zipTree("path_to_jar_file/plain.jar"))
    into("./")
    include "src/main/webapp/**/*.*" [will extract all to root directory]
    include "src/main/webapp/kkk/*.*" [will extract all files in folder named kkk to root directory]
}
Above configuration will extract all file from (jar) "src/main/webapp" to projectRoot/src/main/webapp directory as below:


Thursday, October 21, 2021

Grails 4: How to add Java JAR files to Grails project | How to add an external library or JAR file that is not a grails plugin to the Grails project

Putting the jar in the lib folder should do the trick.

The default lib folder is gone as of Grails 3.0. grails.github.io/grails-doc/3.0.x/guide/single.html#upgrading --> "Dependency resolution should be used to resolve JAR files"
If Grails by default don't take the local .jar libraries located in <GRAILS-APP-DIR>/lib (seems that with Grails >= 3.X the /lib folder default configuration is removed) the easy way to enforce it is modifying build.gradle to add a local directory dependency for it.
For almost all cases is of course better to use the maven repos, but in some cases it's possible to have some other libraries which aren't in a public repo. To do so we have to add these libraries in some lib folder then modify the <GRAILS-APP-DIR>/build.gradle and add something like:
dependencies {
    ...
	// lib folder or any other name one can use 
    compile fileTree(dir: './lib', include: ['*.jar'])
    ...
}
If you want you can use another directory (not /lib) since you're specifying it. Of course use the correct scope (for example for jars which probably already are in your application container class path the scope will be runtime instead of compile)
You can download and drop the jar file into the grails-app/lib directory directly. This should be carefully maintained by someone time to time. Other developers working on the same project might not be aware of its presence. Plus you cannot easily upgrade versions in a transparent manner.

Tuesday, October 12, 2021

Grails 4: How to load datasource configuration from external file in grails 4 In Grails, how do I put my DB username and password in an external property file

I'm trying to take certain database configurations from variables and put them into an external properties file.

I am writing a grails 4.0.11 application. My datasource written in application.groovy file.

I want to load datasource configuration like username,password,DB from an external file. Is there any way to do it in grails 4+ versions.

Here is my datasource configuration in application.groovy using static database name and other properties like username, password etc:-
hibernate {
    cache {
        queries = false
        use_second_level_cache = true
        use_query_cache = true
    }
}

dataSource {
    pooled = true
    jmxExport = true
    dialect = "org.hibernate.dialect.MySQL5InnoDBDialect"
    driverClassName = "org.mariadb.jdbc.Driver"
    username = 'root'
    password = ''
    dbCreate = "update"
    url = "jdbc:mysql://localhost/db2?useUnicode=yes" +
            "&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true" +
            "&useLegacyDatetimeCode=false&serverTimezone=UTC"
    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
        ignoreExceptionOnPreLoad = true
        jdbcInterceptors = "ConnectionState;StatementCache(max=200)"
        defaultTransactionIsolation = Connection.TRANSACTION_READ_COMMITTED // safe default
        abandonWhenPercentageFull = 100 // settings are active only when pool is full
        removeAbandonedTimeout = 120
        removeAbandoned = true
        logAbandoned = false // causes stacktrace recording overhead, use only for debugging
    }
}
Yes, what we can do that is to put database configurations to a file named db_name.properties under [src/main/webapp] directory with following contents:

db_name=some_data_base_name
db_user=root_user
db_password=some_password

Keeping these information will not load automatically. We have to do something magic to load these information into system.

We can define database configuration for grails 4 in 3 different ways -

1. grails-app/conf/config/application.yml
2. grails-app/conf/application
3. grails-app/conf/application.groovy


So from above list we can easily set our target file to load grails 4 application datasource information because we can write code inside groovy files.

First of all remove any datasource related block from above 2 files and add configuration to grails-app/conf/application.groovy file as early statement with some modification.

Now we will load database information from some properties file. We sill use Properties to load database information from file.

Check below code snippet:
import grails.util.BuildSettings

import java.sql.Connection

grails {
    gorm {
        failOnError = true
        'default' {
            mapping = {
                cache true
                version false
                autoTimestamp false
                id generator:'assigned'
                '*'(cascadeValidate: 'none')
            }
        }
    }
}
Properties ppt = new Properties()
File file = new File(BuildSettings.BASE_DIR.absolutePath + "/src/main/webapp/db.properties")
println("Setting up db name-${file.absolutePath}, exists=${file.exists() ? 1 : 0}")
if (file.exists()) {
    file.getCanonicalFile().withInputStream { InputStream stream ->
        ppt.load(stream)
    }
}
println(ppt)

hibernate {
    cache {
        queries = false
        use_second_level_cache = true
        use_query_cache = true
    }
}

dataSource {
    pooled = true
    jmxExport = true
    dialect = "org.hibernate.dialect.MySQL5InnoDBDialect"
    driverClassName = "org.mariadb.jdbc.Driver"
    username = 'root'
    password = ''
    dbCreate = "update"
    url = "jdbc:mysql://localhost/${ppt.get("db.name", "none_db_selected")}?useUnicode=yes" +
            "&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true" +
            "&useLegacyDatetimeCode=false&serverTimezone=UTC"
    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
        ignoreExceptionOnPreLoad = true
        jdbcInterceptors = "ConnectionState;StatementCache(max=200)"
        defaultTransactionIsolation = Connection.TRANSACTION_READ_COMMITTED // safe default
        abandonWhenPercentageFull = 100 // settings are active only when pool is full
        removeAbandonedTimeout = 120
        removeAbandoned = true
        logAbandoned = false // causes stacktrace recording overhead, use only for debugging
    }
}
In above example I only set database name, you can set anything from that configuration file as I did for database name.

Grails saves datetime as UTC time, but reads it as local server time

Grails saves datetime as UTC time, but reads it as local server time???
The timestamp is read back as local time instead. So if my timezone is +2 UTC and the current local time is 12:30:00, what will be saved to the database is 10:30:00, but when I read it back, it becomes 10:30:00. Does anybody know how to fix this problem so that Grails will read the timestamp back as UTC and convert it accordingly?
I have the following line in my Grails application (BootStrap.groovy) to set the default timezone to UTC:
TimeZone.setDefault(TimeZone.getTimeZone("UTC"))
And above line solved my problem. Now I can set time anything to db and returned back the same date to my domain field

Wednesday, September 29, 2021

GRAILS 4 - how to disable deepvalidate in grails globally | Add ability to control cascading validation independently

How can we disable deepvalidate on global level in grails 4? as in our case on saving one domain object its trying to save all internal domain objects leading to different errors like unique constraint and all.

If GORM entity references some other entities, then during its constraints evaluation (validation) the constraints of the referenced entity could be evaluated also, if needed. There is a special parameter cascadeValidate in the entity mappings section, which manage the way of this cascaded validation happens.

You can do this in three ways
1. Define cascadeValidate as mapping per domain where needed:

class Author {
    Publisher publisher

    static mapping = {
        publisher(cascadeValidate: "none")
    }
}

class Publisher {
    String name

    static constraints = {
        name blank: false
    }
}
The following table presents all options, which can be used:

none: Will not do any cascade validation at all for the association.

default: The DEFAULT option. GORM performs cascade validation in some cases.

dirty: Only cascade validation if the referenced object is dirty via the DirtyCheckable trait. If the object doesn’t implement DirtyCheckable, this will fall back to default.

owned: Only cascade validation if the entity owns the referenced object.
2. It is possible to set the global option for the cascadeValidate:

Globally disable cascadeValidate in Grails 3 or 4 using:

grails {
    gorm {
        failOnError = true
        'default' {
            mapping = {
                cache true
                version false
                autoTimestamp false
                id generator:'assigned'
                '*'(cascadeValidate: 'none') // this one is the option to disable deep validate
            }
        }
    }
}
3. Alternatevely you can disable when call save() or merge() using:

new Account().save(validate: true, deepValidate: false)

Grails gorm reference link:

Reference https://gorm.grails.org/latest/hibernate/manual/#_cascade_constraints_validation

Sunday, October 18, 2020

Grails on Groovy - Clear and Flush Current Hibernate Session Data and Evict All Query Cache Data | Clearing Hibernate Query Cache in Grails

Hibernate already has support for query cache. And we know that when we perform a big task there are huge number queries remain in our cache factory. And more important that in most cases we don't need this caches so as a result cache factory getting full with unusual cache data.
This could be a performance issue - so it's better we clear cache on our own responsibility after a big task completed.
Below are the procedure to flush and clear current session (hibernate session) data so that cache factory have enough space for further execution.
import org.hibernate.SessionFactory
import grails.util.Holders

private static SessionFactory _sessionFactory

static Boolean flushAndClearCache() {
    try {
        sessionFactory.currentSession.flush()
        sessionFactory.currentSession.clear()
        sessionFactory.getCache().evictEntityRegions()
        sessionFactory.getCache().evictCollectionRegions()
        sessionFactory.getCache().evictDefaultQueryRegion()
        sessionFactory.getCache().evictQueryRegions()
        return true
    }
    catch (Throwable ex) {
        log.error(ex.ex)
        return false
    }
}

static <T> T getBean(Class<T> requiredType) {
    try {
        return Holders.applicationContext.getBean(requiredType)
    }
    catch (Throwable e) {
        return null
    }
}

static SessionFactory getSessionFactory() {
    _sessionFactory = _sessionFactory ?: (_sessionFactory = getBean(SessionFactory))
}

Thursday, January 2, 2020

Request Mocking In Grails For Back-end/Background Threads | Mock Request With Session

Request Mocking In Grails For Back-end/Background Threads | Mock Request With Session

package com.pkm.util

import grails.gsp.PageRenderer
import grails.util.Holders
import org.codehaus.groovy.grails.web.servlet.mvc.GrailsHttpSession
import org.codehaus.groovy.grails.web.servlet.mvc.GrailsWebRequest
import org.springframework.web.context.request.RequestContextHolder

import javax.servlet.ServletContext
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpSession
/**
 * Created by pritom on 16/08/2017.
 */
class HibernateRequestUtils {
    static GrailsWebRequest getRequest() {
        return RequestContextHolder.getRequestAttributes()
    }

    static HttpSession getSession() {
        return request?.session
    }

    static void setValueToSession(String key, def value) {
        session.putAt(key, value)
    }

    static def getValueFromSession(String key) {
        return session.getAt(key)
    }

    static boolean isBound() {
        HttpServletRequest.isBound()
    }

    static boolean hasSession() {
        session != null
    }

    static def mock(Closure closure = null) {
        return HttpServletRequest.mock(closure)
    }

    static {
        HttpServletRequest.metaClass.static.with {
            isBound = {
                RequestContextHolder.requestAttributes != null
            }
            mock = { closure = null ->
                HttpServletRequest _request = PageRenderer.PageRenderRequestCreator.createInstance("/page/dummy")
                _request.IS_DUMMY = true
                _request."javax.servlet.include.servlet_path" = "/page/dummy.dispatch"
                GrailsWebRequest webRequest = new GrailsWebRequest(
                        _request,
                        PageRenderer.PageRenderResponseCreator.createInstance(new PrintWriter(new StringWriter())),
                        Holders.servletContext
                ) {
                    private MockedHttpSession _session

                    MockedHttpSession getSession() {
                        if (this._session == null) {
                            this._session = new MockedHttpSession()
                        }
                        return this._session
                    }
                }
                RequestContextHolder.setRequestAttributes(webRequest)
                if (closure) {
                    def returned = closure()
                    RequestContextHolder.resetRequestAttributes()
                    return returned
                }
                return webRequest
            }
        }
    }
}

class MockedHttpSession extends GrailsHttpSession {
    MockedHttpSession() {
        super(null)
    }

    private LinkedHashMap attributes = [:]

    Object getAttribute(String name) {
        attributes[name]
    }

    Enumeration getAttributeNames() {
        Collections.enumeration(attributes.keySet())
    }

    long getCreationTime() {
        0
    }

    long getLastAccessedTime() {
        0
    }

    int getMaxInactiveInterval() {
        0
    }

    ServletContext getServletContext() {
        return Holders.servletContext
    }

    @Deprecated
    String[] getValueNames() {
        [] as String[]
    }

    @Deprecated
    void putValue(String name, Object value) {}

    @Deprecated
    void removeValue(String name) {}

    void invalidate() {}

    boolean isNew() {true}

    void removeAttribute(String name) {
        attributes.remove(name)
    }

    void setAttribute(String name, Object value) {
        attributes[name] = value
    }

    void setMaxInactiveInterval(int arg0) {}
}


And use be like below:


if (HibernateRequestUtils.isBound()) {
    DO YOU CODE IN HTTP REQUEST
}
else {
    HibernateRequestUtils.mock {
        DO YOUR CODE IN MOCK REQUEST AS YOU DO IN REAL REQUEST
    }
}