Thursday, June 9, 2011

Grails, spring-ws, SOAP & HTTP request's content type

If you ever have to use Grails to process a fucked up SOAP request with a content type of application/x-www-form-urlencoded then this post is for you.

p.s. eventually we will stop processing that kind of requests but for now we need it to work so client has time to fix their shit up

Problem with application/x-www-form-urlencoded requests & spring-ws' message factory is that it does not like requests with that content type. Rightly so!

The message factory content type issue is obvious since the exception that it throws at you is pretty self-explanatory. The work-around is pretty easy, define your own messageFactory spring bean that is more lenient on the content type.

But after the content type is sorted you would face the second problem "Premature end of file". It took me a while to figure out what is happening. In retrospect it is actually quite logical. The end of file is referring to the request's input stream which has been consumed by Grails filters before it gets to the message factory. The following filters are responsible for parsing the request and routing, luckily they are also subclasses of OncePerRequestFilter which means you can easily bypass them to avoid input stream been consumed.

  1. grailsWebRequest
  2. urlMapping
  3. hiddenHttpMethod

 

How to use Groovy categories in gsp's

You use Groovy categories in a canonical way in gsp's. i.e. by surrounding all your gsp code inside a call to

<% use(YourCategoryClass) { %>

<% } %>

But it gets troublesome quite soon, especially if the main gsp renders other partial templates.

Luckily there is a way to hook into the view rendering workflow. The trick is to provide your own implementation of View that invoke the call to use categories around the view.render method. To do that you also need to override the default jspViewResolver spring bean with your own implementation of ViewResolver which uses your own implementation of View. Lastly if you need dynamically decide what categories classes to use then you can pass it in the model attribute inside your controller.

The result will look something like this.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 
class MyGrailsViewResolver extends GrailsViewResolver {

    @Override
    protected View loadView(String viewName, Locale locale) {
        new MyView(super.loadView(viewName, locale))
    }

    static class MyView implements View {
        def View view

        MyView(View view) {
            this.view = view
        }

        String getContentType() {
            view.getContentType()
        }

        void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) {
            if (model.categories) {
                use(model.remove('categories')) {
                    view.render model, request, response
                }
            } else {
                view.render model, request, response
            }
        }
    }
}

Thursday, November 25, 2010

Convert GPathResult to String without tag0

In Groovy, you can use groovy.xml.XmlUtil.serialize(GPathResult node)
to convert node to XML String.

But sometimes the XML you end up with contains tag0 namespace all over
the elements. It happens because the doc contains default namespace
with empty prefix, so groovy uses a default prefix which is "tag0".
The XML is still correct but it would be nice to not have to see that
crap. To do so you need to create a new closure with the node and
explicitly declare an empty string namespace. Then use
StreamingMarkupBuilder to convert the newly created closure to String.
The following code is how you would implement that logic.

Thursday, July 8, 2010

Overwrite Inploy app servers' restart command

Inploy (http://github.com/dcrec1/inploy) is a rails deployment
solution. It comes with integration to restart 4 app servers:
* mongrel
* passenger
* thin
* unicorn

I needed a way to change how Inploy restarts passenger since our
passenger's restart file is at a different location.

I could've changed the command inside Inploy's passenger.rb but I
wanted to avoid that as there's good chance that someone in the future
won't know to re-apply the change when they upgrade Inploy.

So I needed a way to monkey patch Inploy's passenger module. My first
attempt was to create my version of the Passenger module and require
the file in rails' environment.rb. That was no good because Inploy's
update command does not seem to bootstrap the whole rails environment
so my override simply wasn't getting loaded.

I had to find another way in to load my module for the deployment
process. It turns out the solution I was looking for is in rake. Since
Inploy's update is just a rake task, I could create a passenger.rake
in Rails.root/lib/tasks and define my restart_server override inside
my custom passenger.rake.

Please let me know if there is a better / proper way to achieve what I
needed. Otherwise hope this helps someone else.

Wednesday, December 9, 2009

My shortcut to open any gem in TextMate with 1 command

Using the implementation from @peepcode's blog on shell method missing as a base.
I've added another action (code snippet below) to open a gem library in TextMate by typing in the name of the gem followed by ".mate".

when /^[A-Za-z0-9_\-\/]+\.mate$/
  # Open the gem in textmate
  # @example
  #   haml.mate
  gem_to_open = command.first.gsub(/\.mate$/, '')
  run "gem which #{gem_to_open} | tail -1 | xargs dirname | sed -e's/$/\\/../' | xargs mate"

Wednesday, November 25, 2009

Download sources jar from maven

We use Maven, when Maven downloads dependencies it doesn't download sources, which I rely on when learn and debug programs....
I was expecting, for what seem a simple thing to me, a flag that I can add in maven's settings files or an option to pass to mvn command.... but I couldn't find the solution (or anything close to it). Don't get me wrong, there are solutions out there, but I just feel it is too much hassle for the task.

So I wrote a little script that go thru my repo and downloads any jar that doesn't have its respective sources :p

Monday, November 23, 2009

ImageMagick and JPEG on OSX

I am not a fan of port or fink so I always install ImageMagick from source.
Recently I came across a problem where ImageMagick fails to identify JPEG's.
The error looks something like this
identify: no decode delegate for this image format

After some digging around it appears I need to install libjpeg and reinstall ImageMagick for JPEG support.
So I downloaded jpegsrc.v7.tar.gz and just run thru the standard configure, make & make install then reinstalled ImageMagick.
After the installation you should be able to see JPEG as one of the supported format via the command "identify -list format".
It should contain something like this.
JPEG* JPEG rw- Joint Photographic Experts Group JFIF format (70)