Grails i18n From Database but Default Back To File
The below code is implemented based on the above link.
class DatabaseMessageSource extends PluginAwareResourceBundleMessageSource {
Ehcache messageCache
def messageBundleMessageSource
#Override
protected MessageFormat resolveCode(String code, Locale locale) {
println code + " : " + locale.language
def messageKey = new MessageKey(code, locale)
def messageFormat = messageCache.get(messageKey)?.value
if (!messageFormat) {
I18nMessage i18nMessage = I18nMessage.findByCodeAndLanguageCode(code, locale.language)
if (i18nMessage)
messageFormat = new MessageFormat(i18nMessage.text)
else
messageFormat = super.resolveCode(code, locale)
messageCache.put new Element(messageKey, messageFormat)
}
return messageFormat;
}
In the resources.groovy file this bean is configured as
shown in the below code.
beans = {
messageCache(EhCacheFactoryBean) {
timeToLive = 500
}
messageSource(DatabaseMessageSource) {
messageCache = messageCache
basename = "WEB-INF/grails-app/i18n/messages"
}
}
In the gsp page g:message is called as shown below
1.<g:message code="someObject.create"/>
2.<g:message code="someObject.create" default="Create"/>
3.<g:message code="someObject.create" args="['']"/>
For the same code given in the g:message tag, 1,2 is not displaying the text given in the database. The 3rd tag usage is showing the text content added in the database. 1 tag is showing the someObject.create. 2 Tag is showing Create value, 3rd tag shows the db text added.
why 1 and 2 notations are not displaying the dynamic value in the database? and also that the resolveCode() is called for 1Time only.
Related
In our application we have a requirement to change the locale on the fly by clicking on button. I have referred the below link and was able to reload labels which are coming from the resource bundle with different locale.
Localization in JSF, how to remember selected locale per session instead of per request/view
But my problem is that we have to call SP to get the data in different language according to locale. So the data is not getting loaded from database when i am reloading my page. I have added my code below which i have written so far.
In XHTML Code:
<p:commandButton id="langbutton" value="#{language.lang}"
actionListener="#{language.langChanged}"
ajax="false" styleClass="loginlangbutton"/>
In Bean Class:
public String langChanged() {
FacesContext context = FacesContext.getCurrentInstance();
if (user != null && user.getLang().equalsIgnoreCase("E")) {
user.setLang("F");
lang = "English";
FacesContext.getCurrentInstance().getViewRoot()
.setLocale(Locale.FRENCH);
this.localeCode = Locale.FRENCH;
} else {
user.setLang("E");
lang = "Français";
FacesContext.getCurrentInstance().getViewRoot()
.setLocale(Locale.ENGLISH);
this.localeCode = Locale.ENGLISH;
}
UserBean uBean = (UserBean) context.getApplication()
.evaluateExpressionGet(context, "#{user}",
UserBean.class);
uBean.setLoginDtl(user);
return FacesContext.getCurrentInstance().getViewRoot().getViewId()
+ "?faces-redirect=true";
}
If we have one controller, let's call it document, that has two methods, one that uploads file and another that shows the uploaded file.
I would like to define a new string in the upload method that checks the size of the file and store a specific type name inside that string.
However I would like to access that string in another method which is the list method to be able to show it.
Here is my code:
Class DocumentController {
def list() {
//Here I would like to access that String to show it on the page
[fileSizeType: fileSizeType]
}
def upload {
//define the new String variable
String fileSizeType = ""
if(fileSize < 1000) {
fileSizeType = "type1.."
} else {
fileSizeType = "type2.."
}
}
}
In the gsp page I would like to access the string this way:
<td><g:link>\${fileSizeType}</g:link></td>
I am getting this error when I try the code above:
No such property: fileSizeType for class: file_down.DocumentController
You need to redirect to the list action while passing your argument in the params.
def upload() {
// simplify with ternary expression
def fileSizeType = (fileSize < 1000) ? "type1.." : "type2.."
redirect action:'list', params:[fileSizeType: fileSizeType]
}
// in your list action
def list() {
[fileSizeType: params.fileSizeType]
}
I'm trying to add data auditing to my Grails project, but it doesn't work. I've read this tutorial on grails site and did everything as described there.
What I have now is a domain class Event looking as simple as this:
class Event {
static auditable = true;
String name;
def onSave = {
println "event inserted";
}
def onChange = {
println "event changed";
}
}
and a method in the main controller:
def addEvent = {
def obj = new Event([name:"Test event 1"]);
if (obj.save(flush:true)){
render "addEvent complete for " + obj.toString();}
else{
render "addEvent failed for " + obj.toString();
obj.errors.allErrors.each {
log.error( it.toString() );
}
}
}
I also added auditLog.verbose = true to the Config.groovy file.
Still when I call this method from my browser, the new event is created in DB, but there is nothing in the audit_log table, nor in the console about this happening.
What am I missing here?
My Integration-Test for my grails application is returning a null object when I try to get a domain object using grails dynamic get method.
This is a simplified example of my problem. Lets say I have a controller TrackerLogController that uses a service TrackerLogService to save an updated Log domain for another Tracker domain.
Domain Tracker:
class Tracker {
int id
String name
static hasMany = [logs: Log]
}
Domain Log:
class Log {
int id
String comment
static belongsTo = [tracker: Tracker]
}
Controller TrackerLogController save:
def TrackerLogService
def saveTrackerLog() {
def trackerId = params.trackerId
def trackerInstance = Tracker.get(trackerId)
Log log = TrackerLogService.saveTrackerLogs(trackerInstance, params.comment)
if( log.hasErrors() ){
//render error page
}
//render good page
}
Service TrackerLogService save:
Log saveTrackerLogs( Tracker tracker, String comment) {
Log log = new Log(tracker: tracker, comment: comment)
log.save()
return log
}
So now I want to write an Integration-Test for this service but I'm not sure if I should be writing one just for the simple logic in the controller (if error, error page else good page) I would think I would write a Unit test for that, and an Integration-Test to check the persistence in the Database.
This is what I have for my Integration-Test:
class TrackerLogServiceTests {
def trackerLogService
#Before
void setUp(){
def tracker = new Tracker(id: 123, name: "First")
tracker.save()
//Now even if I call Tracker.get(123) it will return a null value...
}
#Test
void testTrackerLogService() {
Tacker trackerInstance = Tracker.get(123) //I have tried findById as well
String commit = "This is a commit"
//call the service
Log log = trackerLogService.saveTrackerLogs(trackerInstance , commit)
//want to make sure I added the log to the tracker Instance
assertEquals log , trackerInstance.logs.findByCommit(commit)
}
}
So for this example my trackerInstance would be a null object. I know the Grails magic doesn't seem to work for Unit tests without Mocking, I thought for Intigration-Tests for persistence in the DB you would be able to use that grails magic.
You can't specify the id value unless you declare that it's "assigned". As it is now it's using an auto-increment, so your 123 value isn't used. It's actually ignored by the map constructor for security reasons, so you'd need to do this:
def tracker = new Tracker(name: "First")
tracker.id = 123
but then it would get overwritten by the auto-increment lookup. Use this approach instead:
class TrackerLogServiceTests {
def trackerLogService
private trackerId
#Before
void setUp(){
def tracker = new Tracker(name: "First")
tracker.save()
trackerId = tracker.id
}
#Test
void testTrackerLogService() {
Tacker trackerInstance = Tracker.get(trackerId)
String commit = "This is a commit"
//call the service
Log log = trackerLogService.saveTrackerLogs(trackerInstance , commit)
//want to make sure I added the log to the tracker Instance
assertEquals log , trackerInstance.logs.findByCommit(commit)
}
}
Also, unrelated - don't declare the id field unless it's a nonstandard type, e.g. a String. Grails adds that for you, along with the version field. All you need is
class Tracker {
String name
static hasMany = [logs: Log]
}
and
class Log {
String comment
static belongsTo = [tracker: Tracker]
}
I have a grails application that has a service that creates reports. The report is defined as:
class Report {
Date createDate
String reportType
List contents
static constraints = {
}
}
The service generates a report and populates contents as a list that is returned by createCriteria.
My problem is that my service claims to be saving the Report, no errors turn up, logging says that its all there, but when I go to call show from the controller on that report, it says contents is null.
Another relevant bit, my Service is called by an ActiveMQ message queue. The message originating from my report controller.
Controller:
class ReportController {
def scaffold = Report
def show = {
def rep = Report.get(params.id)
log.info("Report is " + (rep? "not null" : "null")) //says report is not null
log.info("Report content is " + (rep.contents? "not null" : "null")) //always says report.contents is null.
redirect(action: rep.reportType, model: [results: rep.contents, resultsTotal: rep.contents.size()])
}
}
My service that creates the report:
class ReportService {
static transactional = false
static expose = ['jms']
static destination = "Report"
void onMessage(msg)
{
this."$msg.reportType"(msg)
}
void totalQuery(msg)
{
def results = Result.createCriteria().list {
//This returns exactly what i need.
}
Report.withTransaction() {
def rep = new Report(createDate: new Date(), reportType: "totalQuery", contents: results)
log.info("Validation results: ${rep.validate()}")
if( !rep.save(flush: true) ) {
rep.errors.each {
log.error(it)
}
}
}
}
Is there something obvious that I'm missing here? My thought is that since all my unit tests work, that the hibernate context is not being passed through the message queue. But that would generate Exceptions wouldn't it? I've been beating my head on this problem for days, so a point in the right direction would be great.
Thanks,
You can't define an arbitrary List like that, so it's getting ignored and treated as transient. You'd get the same behavior if you had a def name field, since in both cases Hibernate doesn't know the data type, so it has no idea how to map it to the database.
If you want to refer to a collection of Results, then you need a hasMany:
class Report {
Date createDate
String reportType
static hasMany = [contents: Result]
}
If you need the ordered list, then also add in a List field with the same name, and instead of creating a Set (the default), it will be a List:
class Report {
Date createDate
String reportType
List contents
static hasMany = [contents: Result]
}
Your unit tests work because you're not accessing a database or using Hibernate. I think it's best to always integration test domain classes so you at least use the in-memory database, and mock the domain classes when testing controllers, services, etc.