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' {} \;
Tuesday, October 23, 2012
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:
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.
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.
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].
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].
- Stop Tomcat
- Install Log4j on your deployment machine. (package install available for a lot of linux distros)
- 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
- Replace the $CATALINA_HOME/bin/tomcat-juli.jar with that same tomcat-juli.jar you just placed in lib.
- Delete $CATALINA_BASE/conf/logging.properties to prevent the old logging system from being used
- 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!
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:
In the domain's scaffold closure:
def constraints = { myStringField(widget:'textarea') }
Make a file list quickly
Need to write a bunch of filenames to a list (say to build a resources list for a Grails plugin or html page) because you can't include just folders? But you don't want to type them all out individually?
Open that good old standby, cmd.exe or terminal and navigate to the root folder containing the files.
[Windows] command: DIR *.* /s /b > ../yourlistname.LST
[Linux/OSX] command: find * . > yourlistname
You can easily add extensions to the DIR and find commands to find only a particular kind of file (DIR *.js for example) Open in your favorite text editor (why not try notepad++ or textmate) use some regex-replacing..
Lets try removing directories from the file list (this could also be done with additional filters in the find commands above):
And your done.
Open that good old standby, cmd.exe or terminal and navigate to the root folder containing the files.
[Windows] command: DIR *.* /s /b > ../yourlistname.LST
[Linux/OSX] command: find * . > yourlistname
You can easily add extensions to the DIR and find commands to find only a particular kind of file (DIR *.js for example) Open in your favorite text editor (why not try notepad++ or textmate) use some regex-replacing..
Lets try removing directories from the file list (this could also be done with additional filters in the find commands above):
- In notepad++, turn on regular expression searching, and check 'mark line'
- Search for [\w+][\.][\w+], which will bring up every line with a . in it (a valid extension)
- Invert the bookmarking with Search->Bookmark->Inverse Bookmark
- Finally delete the now bookmarked lines without file extensions by Search->Bookmark->Delete Bookmarked Lines
And your done.
Thursday, February 16, 2012
Fun fact: Grails GString's require double quotes
Will work:
def element = "<script type=\"text/javascript\" src=\"${g.resource(dir: 'folder', file: 'file.js')}\"></script>"
out << element.toString()
Wont work:
def element = '<script type="text/javascript" src="${g.resource(dir: "folder", file: "file.js")}"></script>'
out << element.toString()
And by "wont work" the groovy expressions in the GString will not be evaluated, they will be delivered literally. Note the double quotes beginning and ending the GString in the first example.
I knew this. Yet I was dissecting why my unit test was failing for over an hour. Turns out junit can't detect silly human error! Since I re-learnt this lesson, I thought I would share it with you, blogosphere!
def element = "<script type=\"text/javascript\" src=\"${g.resource(dir: 'folder', file: 'file.js')}\"></script>"
out << element.toString()
Wont work:
def element = '<script type="text/javascript" src="${g.resource(dir: "folder", file: "file.js")}"></script>'
out << element.toString()
And by "wont work" the groovy expressions in the GString will not be evaluated, they will be delivered literally. Note the double quotes beginning and ending the GString in the first example.
I knew this. Yet I was dissecting why my unit test was failing for over an hour. Turns out junit can't detect silly human error! Since I re-learnt this lesson, I thought I would share it with you, blogosphere!
Friday, January 20, 2012
Grails Codec file location and extension
If you are just beginning out in Grails development, the creation of custom codecs can greatly increase productivity. Codecs help you code/decode (funny that) strings. Grails ships with a bunch of them already, but when you feel like you want to create you own, greate a groovy class file (extension .groovy), with the name ending in "Codec" in your projects graips-app/utils folder. Remember that if you want to place these files in packages, you will need to create the additional folder structure to match the package structure. A sample codec structure is shown below. This file would be in the folder grails-app/utils/org/mycompany/:
package org.mycompany
import /* imports here */
class SampleCodec{
static encode = { str ->
/* Coding data goes here */
}
static decode = { str ->
/* Decoding data goes here */
}
}
Once you start your grails app, Spring will inject the methods encodeAsSample() and decodeSample() to the Java.lang.String class.
Start creating custom hash codes for your passwords now!
package org.mycompany
import /* imports here */
class SampleCodec{
static encode = { str ->
/* Coding data goes here */
}
static decode = { str ->
/* Decoding data goes here */
}
}
Once you start your grails app, Spring will inject the methods encodeAsSample() and decodeSample() to the Java.lang.String class.
Start creating custom hash codes for your passwords now!
Wednesday, January 18, 2012
JMX and Grails
Developing on windows can sometimes really be a pain. I had found documentation all over the web as to where to place my JVM arguments to make grails accept remote JMX connections while developing in eclipse. Most have you modifying $GRAILS_HOME/bin/grails.bat but I was noticing in Java Visual VM (great tool by the way) that the VM arguments were not changing.
In one of those 'the answer is simple stupid' moments - some clarity was given to me by this page of documentation: http://www.objectpartners.com/2009/05/27/eclipse-setup-for-grails-11-development/
By adding the following string the run configuration for my Grails project:
-Dcom.sun.management.jmxremote -Djava.rmi.server.hostname=<yourHostIPHere> -Dcom.sun.management.jmxremote.port=9004 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false
[Note this is obviously not a production setting, you will NEED AUTHENTICATION in production]
I was able to get jconsole to connect to the remote process. Of course local connections had never been a problem as JMX is enabled locally by default.
For anyone curious, the run configuration for a tutorial project is shown below.
In one of those 'the answer is simple stupid' moments - some clarity was given to me by this page of documentation: http://www.objectpartners.com/2009/05/27/eclipse-setup-for-grails-11-development/
By adding the following string the run configuration for my Grails project:
-Dcom.sun.management.jmxremote -Djava.rmi.server.hostname=<yourHostIPHere> -Dcom.sun.management.jmxremote.port=9004 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false
[Note this is obviously not a production setting, you will NEED AUTHENTICATION in production]
I was able to get jconsole to connect to the remote process. Of course local connections had never been a problem as JMX is enabled locally by default.
For anyone curious, the run configuration for a tutorial project is shown below.
A run configuration for JMX with Grails on Windows Eclipse. |
Subscribe to:
Posts (Atom)