Tuesday, May 29, 2012

gr8conf us discounts available!


I am speaking at the GR8Conf in Minneapolis, which is July 29-31. If you are interested in Groovy and Grails technologies, I highly recommend you come join us!

I have  a discount code you can use, enter code 'GR8RyanVanderwerf' to get the $399 price through July 1. With the price of the NFJS and Spring 2GX conferences continually going up each year, this is a great price!
more info at http://gr8conf.us/index


Tuesday, May 22, 2012

Keeping tidy table and columns in Oracle and Grails

Keeping tidy table and columns in Oracle and Grails...


Found I keep having to match your existing oracle schema (It's not case sensitive, but they create all of their tables and columns in all caps with underscored separating words). This doesn't jive with Grails defaults, where it makes tables and columns in lower case seperated by underscores. For example, of I have a domain object PizzaToppings, grails makes it 'pizza_toppings'.

You can fix it like this in your domain class:

static mapping = {
     table name: 'PIZZA_TOPPINGS'
}

But that gets very tedious, especially if you have to do the same for columns. So why not make it automatically do it for you?

So to fix this you can implement or extend the hibernate 'DefaultNamingStrategy' class:


class MyNamingStrategy extends DefaultNamingStrategy {
    @Override
    String classToTableName(String className) {

        return covertFromCamelCase(super.classToTableName(className))
    }

    String covertFromCamelCase(String input) {
       
        GrailsNameUtils.getNaturalName(input).replaceAll("\\s", "_").toUpperCase();
    }
}

Now add this to your DataSource.groovy:

hibernate {
   
    naming_strategy = com.mycompany.database.oracle.MyNamingStrategy

}

Somehow I remember Oracle being better than it was 15 years ago(10g). Now I find it's obtuse error codes and 31 character column/table name limits highly annoying and antiquated. I think I prefer MySQL 5+ now - and the price, just perfect. I'm guessing 80%+ of people running Oracle don't even need it these days, on small to medium installations. And installing on Ubuntu 64bit current versions, Oracle is just a huge mess. The only give you an RPM for 11g, and for 10g just a 32bit deb file - come on Oracle, what are you doing. Please don't ruin Java like this, or maybe it's too late.


Damn you Android camera app/gallery!

Ok so mad at the Android camera app today. My SD car was full, and the gallery and the app flip out when that happens. If you go into the camera app (while sd card is full), and try to go to the last picture (appears black), then delete it, it will delete ALL of your pictures. Argh! I saved a lot of them with an undelete tool, but I think it's time to go from CM7 to CM9 and see if that helps. Maybe it will help, or maybe it will have more bugs (likely). It seems when the sd card is full, the 'Camera' folder disappears in gallery, but if you free up some space, it re-appears. Not this time, it actually deleted all of my pics. Argh!!

Thursday, May 17, 2012

Groovy web scraping

Groovy web page scraping the easy way. I found this from an example on http://www.maclovin.de/2010/02/robust-html-parsing-the-groovy-way/ and it works quite well even today on Grails 2. This uses Tag Soup 1.2.1 and Groovy's XMLSlurper.

In about 10 lines if code I can scrape the form fields (this one only does inputs and selects) off a web page:


 def tagsoupParser = new org.ccil.cowan.tagsoup.Parser()
        def slurper = new XmlSlurper(tagsoupParser)
        def htmlParser = slurper.parse(config.clientUrl)
        ArrayList inputs = new ArrayList();

        htmlParser.'**'.findAll{
            it.name() == 'input' || it.name() == 'select'
        }.each {
            if (it.attributes().get(id) ) {
                inputs.add(it)
            }
        }

IntelliJ open source license w00t

I almost forgot I applied for this 2 months ago. Jetbrains finally gave me a free IntelliJ 11 open source license today. Wise on their part, now I will have IntelliJ running during my presentations this year at GR8Conf, free advertising for them. I feel eventually SpringSource STS is gaining ground on IntelliJ but I still prefer the Jetbrains product. I've been using it since the first versions and it's come a long way. Too bad I have to ask for a new open source license every year, but hey it's free! Thanks Nadya @ Jetbrains!

Salesforce - metadata gotchas

Found a nice gotcha in salesforce today. If you use the metadata API, and create a new field, you have to stay connected until it is complete. If you create a field, and don't check on it's status until it is done, your field will be gone. I'm assuming this is some sort of self-protection mechanism of salesfoce, who knows:

You have to to some something like this: (Assuming you are using the sf-connector-api)

 while (resultList.get(0).state.value() == 'InProgress') {
                sleep(500)
                resultList = metadataConn.checkStatus(tempList)
                if (resultList.get(0).state.value() == 'Error') {
                    // gather errors
                    throw new MetadataServiceException("Error creating custom field")
                }
            }

Also another nugget I found - you can only create 10 fields at a time. If you want to create more than that, you need to break  your list into chunks of 10. Any yes, you must check until they are successful if you want them to show up ;)

Thursday, May 10, 2012

Salesforce and Grails...

Salesforce integration - it's been a while since I have tried this. I have been thinking about this for a few days about how to integrate Grails is a halfway decent way with Salesforce. It's somewhat surprising there isn't a plugin already for this. After being annoyed with Apache CXF Client for Grails all morning, I sought out to find a better solution.

I did however find a pretty slick library called 'sf-api-connector' by a group calling itself 'TeamLazerBeez'. So far it's working, and is nicely arranged. Instead of installing a bunch of stubs and dealing with WSDL and whatnot (I'm trying to use the metadata API, sorry Soap only ugh!).  After you build it, it will install its jars in your local maven repo (I'd recommend publishing on your company's Artifactory or other maven server instance, because these are not hosted on a public repo). From there I just had to add the dependencies to BuildConfig.groovy, and take care to exclude the 'stax-api' from the dependencies (otherwise it conflicts with the built-in JAXB classes in Java6 or later).

Like so:


        compile ('com.teamlazerbeez:sf-soap-api-connector:trunk-SNAPSHOT') {
            excludes "stax-api"
        }
        build ('com.teamlazerbeez:sf-soap-api-connector:trunk-SNAPSHOT') {
            excludes "stax-api"
        }
        test ('com.teamlazerbeez:sf-soap-api-connector:trunk-SNAPSHOT') {
            excludes "stax-api"
        }
        runtime ('com.teamlazerbeez:sf-soap-api-connector:trunk-SNAPSHOT') {
            excludes "stax-api"
        }


Now, I am trying to figure out why, following their example, I keep getting logon denied. First, I made sure there is a 'Allow API' permission added to my salesforce role in the admin console. Second, I make sure I have an API token generated for my account. Third I make sure I append that token to my password login credentials. Still, no luck - wait I am in the SF Sandbox - How does it know that?

Well I had to dig through their code to find it, but here is an example to make a connection to the sandbox(This is Groovy, so yes this runs!, just make up something for orgId):

ConnectionBundle login(String orgId, String userName, String password)  { 
ConnectionPool<Integer> pool = new ConnectionPoolImpl<Integer>(orgId)
        //TODO use Config.groovy property to switch between Sandbox and regular mode
        pool.configureSandboxOrg(orgId, userName, password, 20)
        ConnectionBundle bundle = pool.getSandboxConnectionBundle(orgId)
        MetadataConnection metadataConn = bundle.getMetadataConnection()
     
        // metadata connection
        List<FileProperties> fileProps = metadataConn
                .listMetadata(Arrays.asList(new ListMetadataQuery("CustomField")))
        for (FileProperties fp: fileProps) {
            System.out.println("Custom field " + fp.getFullName() + " has id " + fp.getId())
        }
        return bundle
}


There ya go. If everything is good, you should see on your console a bunch of custom properties from your Salesforce instance. Go here for more info http://blog.teamlazerbeez.com/2011/03/03/a-new-java-salesforce-api-library/

Wednesday, May 9, 2012

Ahh... found a nice little nugget today related to Grails 2.0.3 - you can't have a domain class with 'DataSource' anywhere in it. I reversed engineered a legacy domain class called 'DataSource' - I figured this would cause a problem with the depenency injection, because there is an injectable object with the same name. I figure 'oh, I'll fool it and prefix the class with something'. Wrong, you can't do that either. It will give you weird compile errors on any class that references the class with 'DataSource' in it. Actually it looks like a compiler error, but under the covers it's actually a NPE in the compiler. Moral of the story is don't have a class name with 'datasource' anywhere in it :)



| Error Error running script run-app: org.codehaus.groovy.grails.cli.ScriptExitException (Use --stacktrace to see the full trace)
| Error java.lang.RuntimeException: Reloading agent exited via exception, please raise a jira
| Error at com.springsource.loaded.agent.ClassPreProcessorAgentAdapter.transform(ClassPreProcessorAgentAdapter.java:91)
| Error at sun.instrument.TransformerManager.transform(TransformerManager.java:188)
| Error at sun.instrument.InstrumentationImpl.transform(InstrumentationImpl.java:424)
| Error at java.lang.ClassLoader.defineClass1(Native Method)
| Error at java.lang.ClassLoader.defineClass(ClassLoader.java:791)
| Error at java.lang.ClassLoader.defineClass(ClassLoader.java:634)
| Error at com.springsource.loaded.ChildClassLoader.defineClass(ChildClassLoader.java:21)
| Error at com.springsource.loaded.TypeRegistry.defineClass(TypeRegistry.java:1055)
| Error at com.springsource.loaded.CurrentLiveVersion.define(CurrentLiveVersion.java:110)
| Error at com.springsource.loaded.CurrentLiveVersion.<init>(CurrentLiveVersion.java:87)
| Error at com.springsource.loaded.ReloadableType.loadNewVersion(ReloadableType.java:369)
| Error at com.springsource.loaded.TypeRegistry.loadNewVersion(TypeRegistry.java:792)
| Error at com.springsource.loaded.agent.ReloadableFileChangeListener.fileChanged(ReloadableFileChangeListener.java:38)
| Error at com.springsource.loaded.agent.Watcher.determineChangesSince(FileSystemWatcher.java:202)
| Error at com.springsource.loaded.agent.Watcher.run(FileSystemWatcher.java:186)
| Error at java.lang.Thread.run(Thread.java:722)
| Error Caused by: java.lang.NullPointerException
| Error at com.springsource.loaded.agent.JVMPlugin.accept(JVMPlugin.java:131)
| Error at com.springsource.loaded.agent.SpringLoadedPreProcessor.preProcess(SpringLoadedPreProcessor.java:99)
| Error at com.springsource.loaded.agent.ClassPreProcessorAgentAdapter.transform(ClassPreProcessorAgentAdapter.java:89)
| Error ... 15 more
| Error java.lang.RuntimeException: Reloading agent exited via exception, please raise a jira
| Error at com.springsource.loaded.agent.ClassPreProcessorAgentAdapter.transform(ClassPreProcessorAgentAdapter.java:91)
| Error at sun.instrument.TransformerManager.transform(TransformerManager.java:188)
| Error at sun.instrument.InstrumentationImpl.transform(InstrumentationImpl.java:424)
| Error at java.lang.ClassLoader.defineClass1(Native Method)
| Error at java.lang.ClassLoader.defineClass(ClassLoader.java:791)
| Error at java.lang.ClassLoader.defineClass(ClassLoader.java:634)
| Error at com.springsource.loaded.ChildClassLoader.defineClass(ChildClassLoader.java:21)
| Error at com.springsource.loaded.TypeRegistry.defineClass(TypeRegistry.java:1055)
| Error at com.springsource.loaded.CurrentLiveVersion.define(CurrentLiveVersion.java:110)
| Error at com.springsource.loaded.CurrentLiveVersion.<init>(CurrentLiveVersion.java:87)
| Error at com.springsource.loaded.ReloadableType.loadNewVersion(ReloadableType.java:369)
| Error at com.springsource.loaded.TypeRegistry.loadNewVersion(TypeRegistry.java:792)
| Error at com.springsource.loaded.agent.ReloadableFileChangeListener.fileChanged(ReloadableFileChangeListener.java:38)
| Error at com.springsource.loaded.agent.Watcher.determineChangesSince(FileSystemWatcher.java:202)
| Error at com.springsource.loaded.agent.Watcher.run(FileSystemWatcher.java:186)
| Error at java.lang.Thread.run(Thread.java:722)
| Error Caused by: java.lang.NullPointerException
| Error at com.springsource.loaded.agent.JVMPlugin.accept(JVMPlugin.java:131)
| Error at com.springsource.loaded.agent.SpringLoadedPreProcessor.preProcess(SpringLoadedPreProcessor.java:99)
| Error at com.springsource.loaded.agent.ClassPreProcessorAgentAdapter.transform(ClassPreProcessorAgentAdapter.java:89)
| Error ... 15 more
| Error java.lang.RuntimeException: Reloading agent exited via exception, please raise a jira
| Error at com.springsource.loaded.agent.ClassPreProcessorAgentAdapter.transform(ClassPreProcessorAgentAdapter.java:91)
| Error at sun.instrument.TransformerManager.transform(TransformerManager.java:188)
| Error at sun.instrument.InstrumentationImpl.transform(InstrumentationImpl.java:424)
| Error at java.lang.ClassLoader.defineClass1(Native Method)
| Error at java.lang.ClassLoader.defineClass(ClassLoader.java:791)
| Error at java.lang.ClassLoader.defineClass(ClassLoader.java:634)
| Error at com.springsource.loaded.ChildClassLoader.defineClass(ChildClassLoader.java:21)
| Error at com.springsource.loaded.TypeRegistry.defineClass(TypeRegistry.java:1055)
| Error at com.springsource.loaded.CurrentLiveVersion.define(CurrentLiveVersion.java:110)
| Error at com.springsource.loaded.CurrentLiveVersion.<init>(CurrentLiveVersion.java:87)
| Error at com.springsource.loaded.ReloadableType.loadNewVersion(ReloadableType.java:369)
| Error at com.springsource.loaded.TypeRegistry.loadNewVersion(TypeRegistry.java:792)
| Error at com.springsource.loaded.agent.ReloadableFileChangeListener.fileChanged(ReloadableFileChangeListener.java:38)
| Error at com.springsource.loaded.agent.Watcher.determineChangesSince(FileSystemWatcher.java:202)
| Error at com.springsource.loaded.agent.Watcher.run(FileSystemWatcher.java:186)
| Error at java.lang.Thread.run(Thread.java:722)
| Error Caused by: java.lang.NullPointerException
| Error at com.springsource.loaded.agent.JVMPlugin.accept(JVMPlugin.java:131)
| Error at com.springsource.loaded.agent.SpringLoadedPreProcessor.preProcess(SpringLoadedPreProcessor.java:99)
| Error at com.springsource.loaded.agent.ClassPreProcessorAgentAdapter.transform(ClassPreProcessorAgentAdapter.java:89)
| Error ... 15 more
| Error java.lang.RuntimeException: Reloading agent exited via exception, please raise a jira
| Error at com.springsource.loaded.agent.ClassPreProcessorAgentAdapter.transform(ClassPreProcessorAgentAdapter.java:91)
| Error at sun.instrument.TransformerManager.transform(TransformerManager.java:188)
| Error at sun.instrument.InstrumentationImpl.transform(InstrumentationImpl.java:424)
| Error at java.lang.ClassLoader.defineClass1(Native Method)
| Error at java.lang.ClassLoader.defineClass(ClassLoader.java:791)
| Error at java.lang.ClassLoader.defineClass(ClassLoader.java:634)
| Error at com.springsource.loaded.ChildClassLoader.defineClass(ChildClassLoader.java:21)
| Error at com.springsource.loaded.TypeRegistry.defineClass(TypeRegistry.java:1055)
| Error at com.springsource.loaded.CurrentLiveVersion.define(CurrentLiveVersion.java:110)
| Error at com.springsource.loaded.CurrentLiveVersion.<init>(CurrentLiveVersion.java:87)
| Error at com.springsource.loaded.ReloadableType.loadNewVersion(ReloadableType.java:369)
| Error at com.springsource.loaded.TypeRegistry.loadNewVersion(TypeRegistry.java:792)
| Error at com.springsource.loaded.agent.ReloadableFileChangeListener.fileChanged(ReloadableFileChangeListener.java:38)
| Error at com.springsource.loaded.agent.Watcher.determineChangesSince(FileSystemWatcher.java:202)
| Error at com.springsource.loaded.agent.Watcher.run(FileSystemWatcher.java:186)
| Error at java.lang.Thread.run(Thread.java:722)
| Error Caused by: java.lang.NullPointerException
| Error at com.springsource.loaded.agent.JVMPlugin.accept(JVMPlugin.java:131)
| Error at com.springsource.loaded.agent.SpringLoadedPreProcessor.preProcess(SpringLoadedPreProcessor.java:99)
| Error at com.springsource.loaded.agent.ClassPreProcessorAgentAdapter.transform(ClassPreProcessorAgentAdapter.java:89)
| Error ... 15 more
| Error java.lang.RuntimeException: Reloading agent exited via exception, please raise a jira
| Error at com.springsource.loaded.agent.ClassPreProcessorAgentAdapter.transform(ClassPreProcessorAgentAdapter.java:91)
| Error at sun.instrument.TransformerManager.transform(TransformerManager.java:188)
| Error at sun.instrument.InstrumentationImpl.transform(InstrumentationImpl.java:424)
| Error at java.lang.ClassLoader.defineClass1(Native Method)
| Error at java.lang.ClassLoader.defineClass(ClassLoader.java:791)
| Error at java.lang.ClassLoader.defineClass(ClassLoader.java:634)
| Error at com.springsource.loaded.ChildClassLoader.defineClass(ChildClassLoader.java:21)
| Error at com.springsource.loaded.TypeRegistry.defineClass(TypeRegistry.java:1055)
| Error at com.springsource.loaded.CurrentLiveVersion.define(CurrentLiveVersion.java:110)
| Error at com.springsource.loaded.CurrentLiveVersion.<init>(CurrentLiveVersion.java:87)
| Error at com.springsource.loaded.ReloadableType.loadNewVersion(ReloadableType.java:369)
| Error at com.springsource.loaded.TypeRegistry.loadNewVersion(TypeRegistry.java:792)
| Error at com.springsource.loaded.agent.ReloadableFileChangeListener.fileChanged(ReloadableFileChangeListener.java:38)
| Error at com.springsource.loaded.agent.Watcher.determineChangesSince(FileSystemWatcher.java:202)
| Error at com.springsource.loaded.agent.Watcher.run(FileSystemWatcher.java:186)
| Error at java.lang.Thread.run(Thread.java:722)
| Error Caused by: java.lang.NullPointerException
| Error at com.springsource.loaded.agent.JVMPlugin.accept(JVMPlugin.java:131)
| Error at com.springsource.loaded.agent.SpringLoadedPreProcessor.preProcess(SpringLoadedPreProcessor.java:99)
| Error at com.springsource.loaded.agent.ClassPreProcessorAgentAdapter.transform(ClassPreProcessorAgentAdapter.java:89)
| Error ... 15 more
| Error java.lang.RuntimeException: Reloading agent exited via exception, please raise a jira
| Error at com.springsource.loaded.agent.ClassPreProcessorAgentAdapter.transform(ClassPreProcessorAgentAdapter.java:91)
| Error at sun.instrument.TransformerManager.transform(TransformerManager.java:188)
| Error at sun.instrument.InstrumentationImpl.transform(InstrumentationImpl.java:424)
| Error at java.lang.ClassLoader.defineClass1(Native Method)
| Error at java.lang.ClassLoader.defineClass(ClassLoader.java:791)
| Error at java.lang.ClassLoader.defineClass(ClassLoader.java:634)
| Error at com.springsource.loaded.ChildClassLoader.defineClass(ChildClassLoader.java:21)
| Error at com.springsource.loaded.TypeRegistry.defineClass(TypeRegistry.java:1055)
| Error at com.springsource.loaded.CurrentLiveVersion.define(CurrentLiveVersion.java:110)
| Error at com.springsource.loaded.CurrentLiveVersion.<init>(CurrentLiveVersion.java:87)
| Error at com.springsource.loaded.ReloadableType.loadNewVersion(ReloadableType.java:369)
| Error at com.springsource.loaded.TypeRegistry.loadNewVersion(TypeRegistry.java:792)
| Error at com.springsource.loaded.agent.ReloadableFileChangeListener.fileChanged(ReloadableFileChangeListener.java:38)
| Error at com.springsource.loaded.agent.Watcher.determineChangesSince(FileSystemWatcher.java:202)
| Error at com.springsource.loaded.agent.Watcher.run(FileSystemWatcher.java:186)
| Error at java.lang.Thread.run(Thread.java:722)
| Error Caused by: java.lang.NullPointerException
| Error at com.springsource.loaded.agent.JVMPlugin.accept(JVMPlugin.java:131)
| Error at com.springsource.loaded.agent.SpringLoadedPreProcessor.preProcess(SpringLoadedPreProcessor.java:99)
| Error at com.springsource.loaded.agent.ClassPreProcessorAgentAdapter.transform(ClassPreProcessorAgentAdapter.java:89)
| Error ... 15 more




Thursday, May 3, 2012

Ubuntu 12.04

Running Ubuntu 12.04 Precise Pangolin release finally.. I tried out the Beta early, because I had 10.04 and nothing on my work laptop MSI GT683 machine worked with it. Now everything is working except the fancy lights, turbo, and eco modes.

Still getting used to Unity, I don't like how it combines running apps with an app toolbar - it's difficult to tell what is open or not by looking at it. I think I prefer the older Gnome 2 interface, maybe because it's just simpler and what I know. I did try MATE on LinuxMint12, although neat, it was incomplete and buggy. I found LinuxMint 12's default interface even more odd than unity, like a couple mismatched interfaces thrown together - I didn't get it.

I  suppose I'll stick it out with Unity a bit longer.