Monday, August 29, 2011

My latest Web service is LIVE

It's been a while since i last posted. But i have been busy working on this new service.

http://www.hugglehub.com

The service is all about making it easy to share you photos with your parents.

Check it out let me know what you think.

Monday, May 16, 2011

User tracking logging in Grails

Hi peeps

Thought i would just do a quick post about how to create a custom logging filter for logging which pages a user went to.

First setup log4j config to add a new apppender nd logger called utlog (usage tracking)

 def utLog = "${System.properties.getProperty('catalina.base')}${File.separator}logs${File.separator}utlog.log"  
println utLog
log4j = {
appenders {
rollingFile name: 'utlog', file: utLog, layout: pattern(conversionPattern: '%d{dd-MM-yyyy HH:mm:ss,SSS}|%p|%c{1}|%X{userId}|%X{sessionId}|%m%n'), maxFileSize: '10MB', threshold: org.apache.log4j.Level.DEBUG
console name: 'stdout', layout:pattern(conversionPattern: '%d{dd-MM-yyyy HH:mm:ss,SSS}|%p|%c{1}|%X{userId}|%X{sessionId}|%m%n'), threshold: org.apache.log4j.Level.DEBUG
}
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'
warn 'org.mortbay.log'
info utlog: ['ut'],additivity:true
}



Next create a filter that uses Spring security plugin to fetch the current logged in user:

 class UsageTrackingFilters {  
def springSecurityService
private static final Log usagetrackingLog = LogFactory.getLog('ut')
def filters = {
all(controller: '*', action: '*') {
before = {
String sessionId = RequestContextHolder.getRequestAttributes()?.getSessionId()
if (sessionId) {
MDC.put('sessionId', sessionId)
}
if (springSecurityService.isLoggedIn()) {
def userId = springSecurityService.getPrincipal().id
MDC.put('userId', userId + "")
}else{
MDC.put('userId', "0")
}
usagetrackingLog.info(request.getRequestURI())
}
after = {
}
afterView = {
MDC.remove('sessionId')
MDC.remove('userId')
}
}
}
}


That is it

Saturday, February 26, 2011

Setup Amazon linux for Grails

Install mysql

yum install mysql mysql-server mysql-libs
service mysqld start
chkconfig --levels 235 mysqld on
mysql_secure_installation



Install apache

sudo yum install httpd httpd-devel

add /etc/httpd/conf.d/proxy_ajp.conf

With this in it:

<Ifmodule mod_proxy_ajp.c>
ProxyRequests On
ProxyVia On

<Location />
Order allow,deny
Allow from all
ProxyPass ajp://localhost:8009/
ProxyPassReverse ajp://localhost:8009/
</Location>

</Ifmodule>

Wednesday, October 20, 2010

Grails GORM trick: Use read() rather than get() on updates

Hi

So i discovered that it might be a good idea use read() on your update method.

So use

def person = Person.read(params.id)

instead of

def person = Person.get(params.id)

The consequence of this is that hibernate dirty checking is turned off. So to save your domain object you MUST call save(). So if you cancel the update for any reason without calling save() you do not have to to worry about grails persisting things automatically due to dirty checking :)

Hope this helps

Sunday, October 17, 2010

GORM gotcha: Many to Many mapping causing new Domain to be saved

Hi All

I came across a new Grails GORM subtle gotcha this week.

I was creating a new Domain object and it was still getting persisted to the database even though i was not calling save().

This is not normal behavior for NEW objects. As you may or may not be aware this is the behavior when updating objects though. So i was quite surprised by this and did some trials in trying to fix the problem.

First calling discard() on my NEW object was the first try. But that was a guess and i knew really it would not work. Because that object not yet associated with the session. And it didn't. So i finally found the problem.

This was all to do the the many to many relationship that was setup on the domain object.

So for example i have somethings like this:

class Location {

static hasMany = [posters:Poster]

String name

}

class Poster {

static belongsTo = [Location]

static hasMany = [locations:Location]

String name

}




So in my controller i allow a user to select multiple locations. These locations all get added to the new Poster in this line of code:

Poster poster = new Poster(params)




So if i then have some business logic that decides that i do not want to create this new Poster i just need to not call save right. Turns out that is wrong.

Because of the many to many relationship between Location and Poster. Poster has been assoiated with the locations. So the locations are now dirty and will get persisted at the end of the transaction. This will cascade to my new Poster and save it.

So to fix this you need to discard the Location objects so they do not save your Poster object.

Poster poster = new Poster(params)

if(businessLogicValidate() == false){

poster.locations.each{Location l ->
l.discard();
}

}else{

poster.save()

}





Hope this helps someone.

Thursday, October 14, 2010

Stored procedures on Amazon RDS

Been a long time since i blogged but need to document this pain in the arse.

So for a new project i need to create a mysql function (same for stored proc) on amazon RDS.

When i tried to install it i got this error:

ERROR 1419 (HY000) at line 3: You do not have the SUPER privilege and binary logging is enabled (you *might* want to use the less safe log_bin_trust_function_creators variable)

So to get them to install you need to set that database parameter to ON. However to do that is not so simple.

Lucky for you people i have found out how to do it and here are the steps:

1) Install the RDS CLI tools. I installed these on my EC2 instance.

Download from here:
http://developer.amazonwebservices.com/connect/entry.jspa?categoryID=294&externalID=2928

They are java based and so you need have Java running. Plus they need your amazon key and secret key. Once you have them installed following the readme do the following:

Important!! make sure you set the AWS region you are working in.
Eg export EC2_REGION=ap-southeast-1

2) create a new parameter group

rds-create-db-parameter-group peters-params -f mysql5.1 -d "peters params"

3) modify the log_bin_trust_function_creators to be set to ON

rds-modify-db-parameter-group peters-params --parameters="name=log_bin_trust_function_creators, value=on, method=immediate"

4) change your running db instance to use the new param group

rds-modify-db-instance petersdbinstance --db-parameter-group-name=peters-params

5) restart the instance

rds-reboot-db-instance petersdbinstance


That will allow you to create a function or stored procedure:

Some point about the function / stored proc:

You need to specify the DETERMINISTIC stuff and you need to add a DEFINER=CURRENT_USER


DELIMITER $$
DROP FUNCTION IF EXISTS `sayhello`$$
CREATE DEFINER=CURRENT_USER FUNCTION `sayhello`(param1 VARCHAR(120))
RETURNS VARCHAR(120)
NOT DETERMINISTIC
READS SQL DATA
BEGIN
RETURN CONCAT('Hello, ',s,'!');

END$$
DELIMITER ;


This works for me hope it helps

Monday, November 2, 2009

how to setup clover with multi-module maven project and build with bamboo

Ok so i figured how to setup clover with maven on a mulit-module project with putting the config in a maven profile:

<profile>
<id>clover</id>
<build>
<plugins>
<plugin>
<groupId>com.atlassian.maven.plugins</groupId>
<artifactId>maven-clover2-plugin</artifactId>
<configuration>
<targetPercentage>${clover.coverage.percent}</targetPercentage>
<snapshot>/development/build-server/clover/${groupId}-${artifactId}/clover.snapshot</snapshot>
<generateHtml>true</generateHtml>
<generateXml>true</generateXml>
<baseDir>${project.basedir}</baseDir>
<licenseLocation>/development/build-server/clover/clover.license</licenseLocation>
</configuration>
<executions>
<execution>
<id>clover</id>
<goals>
<goal>setup</goal>
<goal>snapshot</goal>
</goals>
</execution>
<execution>
<phase>verify</phase>
<goals>
<goal>aggregate</goal>
<goal>clover</goal>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>

</plugins>
</build>
</profile>


Simply drop that into your profiles section in your pom. You will need to change the paths of where you have put your clover licence and where you want the snapshots to be stored. Then when you want to run it use this command.

mvn -P clover install


Bamboo

Setup bamboo as normal but make sure you don't let bamboo clear out your build directory each time or clover won't work. So untick the option to clean out the build directory each time.