Tuesday, October 23, 2012

Simple Scripts for replacing html tags

I recently had to upgrade a tag library we were using. However the latest version had refactored out some of the tags into a separate tag library. I needed to do two things:

1) Add a reference to the new tag library on each page that had previously been using the base library
2) Change the tags using the old library to update to use the new prefix

#Add a new line (using a\ option) to the files containing reference to struts-jquery-tags

find . -type f \( -iname "*.tag" -or -iname "*.jsp" \) -print -exec sed -i '/struts-jquery-tags\"\s%>/ a\
<%@ taglib prefix=\"sjg\" uri=\"\/struts-jquery-grid-tags\" %>' {} \;

#Find and replace references to the old sj:grid to use the new :sjg:grid
find . -type f \( -iname "*.tag" -or -iname "*.jsp" \) -print -exec sed -i 's/sj:grid/sjg:grid/g' {} \;

#Finally strip out some redundant information from header tags
find . -type f \( -iname "*.tag" -or -iname "*.jsp" \) -print -exec sed -i 's/head\suseJqGridPlugin=\"true\"/head/g' {} \;

Wednesday, April 25, 2012

Script for fast Mysql Dump

This command will create a file named mysqldum.sql in the current dirrectory:


mysqldump DBNAME --add-drop-table -u USERNAME-p > mysqldump.sql

Remember when going to older versions of mysql to do a search and replace for "USING BTREE" as it is not supported in older mysql installs.

This file can then be imported via:

 mysql DBNAME -u USERNAME -p < mysqldump.sql 

This post is mostly for my own information, I keep forgetting the exact order of the arguments!

Friday, March 30, 2012

Flowplayer 201 Error in Commercial Build

Our site had been a long time customer of flowplayer. We have a commercial license. However the person who had purchased said license was no longer at the company and the account was tied to her email address. We didnt get the memo when flowplayer moved its builds to amazon s3.

Luckily my browser remembered the password to the account site - and I changed the location of the flash builds. However they were still using an older version, 3.2.5-0. After changing the links, the player would load up, but report a 201 error,:

201, Unable to load stream or clip file, connection failed, clip: '[Clip]

The fix? I needed to download and use the newer commercial builds found on the account page under "Commercial license. v3.2" - that, along with the new javascript libraries associated (3.2.8 at the time of writing) got things going again.

Monday, March 26, 2012

Detecting environment for Google Web Toolkit

Have a piece of code that you want to run only when running in Hosted Mode? I made a small utility class that uses one method exposed in the Google Web Toolkit API to do just that.


import com.google.gwt.core.client.GWT;


/**
 * Utility Class to help write debugging code
 * References to these function could be searched for and removed when deploying to production for increased speed.
 * @author Jason Lambert
 *
 */
public class Development {
public static boolean isDevelopmentEnvironment() { return !GWT.isScript(); } //detect hosted mode


}

Inspired by how Grails handles development, test and production environments, I  made this quick static utility function.

GWT.isScript detects if the current environment is running in compiled byte code or not. useful for switching to download local resources when perhaps same origin policy (SOP) prevents your code from downloading data from external databases or servers.

Thursday, March 15, 2012

Tomcat SEVERE: Error listenerStart - Debugging.

From my travels across Google, this error is common. In Grails applications it is almost always from a bad datasource.groovy file. This error is the non descriptive string you receive when deploying your servlet (Grails, Spring, Otherwise) to tomcat (probably version 5.5 or higher). The servlet probably runs fine in development mode on your machine. How do we debug it? Read on.

Lets start by getting more useful error messages from Tomcat.
Tomcat by default uses java.util.logging, which is giving you the basic error messages along the lines of...


DATETIME org.apache.catalina.core.StandardContext startInternal
SEVERE: Error listenerStart
DATETIME org.apache.catalina.core.StandardContext startInternal
SEVERE: Context [/AppName] startup failed due to previous errors

Lets configure tomcat to use log4j, which will produce a much better call stack to debug. Taken from advice here, I'll paraphrase [read the source material for a full understanding however].


  1. Stop Tomcat
  2. Install Log4j on your deployment machine. (package install available for a lot of linux distros)
  3. Download tomcat-juli-adapters.jar and tomcat-juli.jar from the extras section of the tomcat website (For version 7.0 that extras page is here) and place them into the $CATALINA_HOME/lib folder
  4. Replace the $CATALINA_HOME/bin/tomcat-juli.jar with that same tomcat-juli.jar you just placed in lib.
  5. Delete $CATALINA_BASE/conf/logging.properties to prevent the old logging system from being used
  6. Start Tomcat


In my case, the error stack now looked like the following. As you can see like an idiot I had left the driverClassName to the grails 2.0 default of  org.h2.Driver instead of the com.mysql.jdbc.Driver required to connect to a mysql service. Interestingly my eclipse/tomcat development setup was forgiving me and loading the correct driver anyway - be warned!

SEVERE: Exception sending context initialized event to listener instance of class org.codehaus.groovy.grails.web.context.GrailsContextLoaderListener
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'transactionManagerPostProcessor': Initialization of bean failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creati$
        at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
        at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:334)
        at java.util.concurrent.FutureTask.run(FutureTask.java:166)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
        at java.lang.Thread.run(Thread.java:679)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'transactionManager': Cannot resolve reference to bean 'sessionFactory' while setting bean property 'sessionFactory'; nested exception is org.sp$
        ... 6 more
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sessionFactory': Cannot resolve reference to bean 'hibernateProperties' while setting bean property 'hibernateProperties'; nested exception is $
        ... 6 more
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'hibernateProperties': Cannot resolve reference to bean 'dialectDetector' while setting bean property 'properties' with key [hibernate.dialect];$
        ... 6 more
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dialectDetector': Invocation of init method failed; nested exception is org.springframework.jdbc.support.MetaDataAccessException: Error while e$
        ... 6 more
Caused by: org.springframework.jdbc.support.MetaDataAccessException: Error while extracting DatabaseMetaData; nested exception is org.apache.commons.dbcp.SQLNestedException: Cannot create JDBC driver of class 'org.h2.Driver' for connect URL '$
        ... 6 more
Caused by: org.apache.commons.dbcp.SQLNestedException: Cannot create JDBC driver of class 'org.h2.Driver' for connect URL 'jdbc:mysql://xxx.xx.xx.xx:3306/mydatabasename?autoreconnect=true&zeroDateTimeBehavior=convertToNull'
        at org.apache.commons.dbcp.BasicDataSource.createConnectionFactory(BasicDataSource.java:1452)
        at org.apache.commons.dbcp.BasicDataSource.createDataSource(BasicDataSource.java:1371)
        at org.apache.commons.dbcp.BasicDataSource.getConnection(BasicDataSource.java:1044)
        ... 6 more
Caused by: java.sql.SQLException: No suitable driver
        at java.sql.DriverManager.getDriver(DriverManager.java:279)
        at org.apache.commons.dbcp.BasicDataSource.createConnectionFactory(BasicDataSource.java:1437)
        ... 8 more

Tuesday, February 21, 2012

Searching Multiple Data Sources in Grails

Have you got domain classes mapped to multiple datasources? The Searchable plugin will mysteriously not be building indexes for domain classes in your secondary datasources by default. The following explains a way to change the behavior.

This is taken from my personal experience, and information compiled from a helpful thread archived on Grails, found here. We are going to need to redefine some beans.

Step 1:
Open conf/spring/resources.groovy


add in the following bean:


import org.compass.gps.device.hibernate.HibernateGpsDevice //need this import for new datasource
import grails.plugin.searchable.internal.compass.config.SessionFactoryLookup //need this import to get correct sessionfactory class


beans = {


/* ~ your other beans here */



compassGpsDevice(HibernateGpsDevice) { bean ->
bean.destroyMethod = "stop"
name = "hibernate"
sessionFactory = { SessionFactoryLookup sfl ->
sessionFactory = ref('sessionFactory_datasourceName') 
}//replace datasourceName with the name of the datasource as defined in conf/DataSource.groovy
fetchCount = 5000
}
}


Step 2:
You could stop here if this was the only datasource that contained indexable classes, but continue to add each compassGPSdevices for each additional datasource (including the default), making sure they are unique names ie:



anotherUniquecompassGpsDevice(HibernateGpsDevice) { bean ->
bean.destroyMethod = "stop"
name = "unqiueHibernateName"
{ SessionFactoryLookup sfl ->
sessionFactory = ref('sessionFactory_uniquedatasource') 
}
fetchCount = 5000
 }


then finally we need to combine all of these datasources into one SingleCompassGps for searchable. Add this last bean:


import org.compass.gps.impl.SingleCompassGps

compassGps(SingleCompassGps) {
compass = ref('compass')
gpsDevices = [compassGpsDevice, anotherUniqueCompassGpsDevice /* ~add the other sources in here */ ]
}

Thanks to the original thread for guidance. Hopefully this compilation of guidance will help someone else save some time. The major additions beyond the original thread are to use the sessionfactorylookup. You can see these objects in SearchableGrailsPlugin.groovy - we are simply re defining them with new datasources!





Friday, February 17, 2012

Undocumented? Grails scaffolding feature. Widgets

Present in old docs, but weirdly not the latest, you can request a different widget on scaffolded pages for your domain class.

In the domain's scaffold closure:


def constraints = {
        myStringField(widget:'textarea')
}