Wednesday, October 31, 2007

Logging WebService Methods Called in Axis using a Handler

When you look in the access log of a server hosting web services, you are unable to see which web service methods, that are actually called. This is due to the fact that SOAP requests are HTTP POST requests, where the method called is a function of the SOAP message posted.

If you are using axis, there is a simple way to log which methods that are called. This can be done by implementing a handler and configure it into the chain of handlers, that axis executes on each request.

Here is the handler:
package com.blogspot.techpolesen.webservice.util;

import org.apache.axis.AxisFault;
import org.apache.axis.Handler;
import org.apache.axis.MessageContext;
import org.apache.axis.handlers.BasicHandler;
import org.apache.log4j.Logger;

public class LogMethodCalledAxisHandler extends BasicHandler {
private static final Logger LOG = Logger.getLogger("com.blogspot.techpolesen.webservice.util.LogMethodCalledAxisHandler");

public void invoke(MessageContext msgContext) throws AxisFault {
Handler serviceHandler = msgContext.getService();
String serviceName = serviceHandler == null ? null : serviceHandler.getName();
String methodName = msgContext.getOperation().getMethod().getName();
LOG.info("SOAP Method called: [" + methodName + "] in [" + serviceName + "]");
}
}
You then package this class in your war and put this into your axis deployment wsdd file:
<requestFlow>
<handler type="java:com.blogspot.techpolesen.webservice.util.LogMethodCalledAxisHandler"/>
</requestFlow>
This will make axis call this handler as part of the chain of handlers called for each SOAP request. In my implementation I simply log service name and method called using log4j.

BTW: This post was done with axis1 as the basis. In axis2, the handler concept has shifted a bit into modules and deployment is also done differently than the wsdd.

Project Planning with OpenProj

Some time ago I stumpled upon OpenProj, an open source, free project planning tool like Microsoft Project. Recently, I took it for a ride, just to see what it can do. And I must say, that it looks really complete and nice. So, if you are into gantt chart control and like to avoid M$, I think you should give OpenProj a try.

Monday, October 29, 2007

Flex Trace and Logging

Here is a bit of collected information about how to trace and log in flex.

Flex Tracing
This is easy. There is a global trace() function, which you can call from anywhere. The output from trace calls only appears when the flash applikation in run on either the debugger version of the flash player or the debugger version of the standalone player.

There are two options for getting at the output: Either through the flex debugger or by having it go into a file. Of the two, I have found the latter the most useful.

Flex trace into a file
In your home directory, you put a file called mm.cfg, which contains the following three lines:
ErrorReportingEnable=1
TraceOutputFileEnable=1
MaxWarnings=1
And when you run your flash application on a debug player, the flash runtime will open and write to a file at this path: "$HOME/.macromedia/Flash_Player/Logs/flashlog.txt". You can then "tail -f" this file and see all the trace.

Flex trace through debugger
Well, you start the fdb debugger binary and type run. After this, you start your flash application in a debugger version of a player and connects to the debugger through the dialog that opens. You then switch back to the fdb console and type continue (twice). Trace will then flow out on the fdb console.

Only problem is, that on linux, the fdb console disconnects at random intervals (or, most often, just before you reach the trace information you are interested in).

Flex trace in the FlashTracer firefox plugin
Firefox has a nice plugin called FlashTracer, which can show the contents of the trace file enabled with the mm.cfg file. This is really nice, as you need not tail the file and can view the output along the application.

If you are running linux, you need a special built version. Alessandro Crugnola has a nice blog entry about how to install the linux built version of FlashTracer.

Flex Logging
While you use tracing mostly for debugging purposes, logging can be done on several levels and hence be used for more sophisticated purposes. There is a complete mx.logging package in flex2, which provides the main logging functionality of flex.

Two central abstractions here are ILogger which abstracts something that you can log to and ILoggingTarget, which abstracts something that can accept logs and do something with them. When logging to an ILogger, you can do it as debug, info, warn, error or fatal. In addition, an ILogger has a category, which is a hierarchic name. A log target can have filters on which categories they "let through", and a level setting, that specifies which of the five debug, info, warn, error and fatal levels that it "let through".

In the mx.logging.targets package, there are two (very) simple logging targets implemented. One which goes to trace output, and one old, deprecated minidebug-based one, which should never have been in the public flex2 api.

Good thing is, that you can implement your own log targets. I have written an example on how to send logs to the server from a flex application using a log target implementation, which might be helpful.

Friday, October 26, 2007

Keeping Mongrel Alive when it Keeps Crashing

For some time, I have had a problem with a rails deployment of mine. It is running apache in front of several mongrel instances. Problem is, the mongrel processes simply disappear, without a trace. Their pid files are still lying around. The log shows nothing. There appears to be no system in it. There can be weeks between and there can be days between. It can happen in the night and it can happen at daytime. Sucks.

Today, I sat down and wrote a simple bash shell script, which performs some basic surveillance and a restart, if mongrel processes disappear. Would be more nice for them not to crash, I know.

If you have the same problem, I here give you my quick and simple script. It even notifies by email when a restart has been performed. Of course, comments on improvements are more than welcome.
#!/bin/bash

SLEEP_INTERVAL=60
PID_DIR=/var/opt/rails/yourapp/log
CLUSTER_CTL_CMD=/etc/init.d/mongrel_cluster_ctl
NOTIFY_EMAIL=youremail@goes.here

if [ $USER != "root" ]; then
echo "I need to be run as root. From here on, I will quickly grow cold."
exit 1
fi

# Act a bit like a daemon, by ignoring HUP and
# being nice and releasing yourself to / in case someone needs to
# unmount where you were started.
#
trap 1
cd /

function restart_mongrels() {
echo "stopping..."
$CLUSTER_CTL_CMD stop
echo "stopped, will sleep 10 secs"
sleep 10
echo "done sleeping, will remove any old pid files and start mongrels"
rm -f $PID_DIR/mongrel.*.pid
$CLUSTER_CTL_CMD start
echo "issued start, will wait 10 secs more, to let it fire up properly"
sleep 10
mail -s "Mongrels restarted" $NOTIFY_EMAIL <<ENDMAIL
At `date` your mongrel instanses were restarted.
Have a blast digging around in the logfiles trying to find out why...
.
ENDMAIL
}

while (true); do
# start by checking, that there are ANY pidfiles around
ls $PID_DIR/mongrel.*.pid > /dev/null 2>&1
ANY_PID_FILES=$?
if [ $ANY_PID_FILES -ne 0 ]; then
echo "`date`: oops, found no pid files at all in $PID_DIR, going for a restart"
restart_mongrels
fi

# if there are pidfiles, check that their processes are running
for pidfile in $PID_DIR/mongrel.*.pid ; do
# check that pidfile is still here (as in, we remove them all deeper in this for-loop, if mongrels are down)
if [ ! -f $pidfile ]; then
echo "skipping missing pid file: $pidfile (can happen after a restart)"
continue
fi

PID=`cat $pidfile`
ps -p$PID > /dev/null
PID_CHECK_RESULT=$?
if [ $PID_CHECK_RESULT -ne 0 ]; then
echo "`date`: Oops, did not find process for pid $PID in pid file $pidfile, will restart mongrels"
restart_mongrels
fi
done
echo "`date`: Checked all mongrel instances are up an running, will sleep for $SLEEP_INTERVAL seconds and check again...Zzzz"
sleep $SLEEP_INTERVAL
done

Wednesday, October 17, 2007

Cool ActiveRecord Completion Support

Previously I have complained about Rails and how the attributes of a model aren't properly visible on the model as such (because they are automatically added at runtime by matching it to its table). The only way for me to get a complete picture of a model, is to look both into the migrations that work on the table of the model and into the model itself, and then combine these views.

Well, seems like others had the same trouble but did something about it. Tor Norbye show some screenshots of the latest new Netbeans support for ActiveRecord completion here, which actually does this. Netbeans is looking into the migrations and into the model, and then supports code completion in the IDE with all the information it collects. Supposedly it does not stop at the migration that creates a table, but also recognizes later migrations that change the schema. Things like rename of columns.

Cool! Simply cool!

Monday, October 15, 2007

Blog Action Day: City Bikes in Copenhagen Denmark

Today is Blog Action Day 2007 about environment, and this is my contribution.

I live in Denmark in the city of Copenhagen, and I would like to put emphazis on something simple that can be done for the environment. Here, we have city bikes, which are bikes you can grab and use to get around, without any expense. It works like a shopping cart. You put in a coin to get the cart out of its holder, and get the coin back, when you replace the bike in another holder somewhere in the city. Nice and easy!

What this can do for the environment is not so much the lesser use of cars to get around, but what else it brings. Like the fact, that there is emphazis on making it more easy to get around in Copenhagen on bikes. Something that is good for all bikers, and which might bring more bikers and less cars around.

So, why not start this up in your city?

Wednesday, October 03, 2007

No Project-Level Encoding in IDEA 7

In short: If you would like to be able to set a charset encoding for your sources at the project level in IDEA, I urge you to vote for this jira issue at JetBrains.

Some time ago I wrote and released the encoding-plugin for IDEA to let you set a project encoding that is then checked against the IDE-level setting.

This plugin was a response to the old issue on the need for a real project level charset encoding in IDEA, and with the relese of my plugin, a new debate was spawned on the jira issue at JetBrains. Suddenly, someone discussed it and JetBrains seemed to take notice.

Well, the other day I received a mail notice from the jira instance at JetBrains, telling me, that the issue have been moved to be fixed in "Next IDEA Version" (which is the one after v7). Dammit!

Tuesday, October 02, 2007

10 Areas Where Rails Fails

Having done both some real world Rails development and a lot of real world Java development, I have accumulated some experience, that I would like to share. In particular about where rails fails to deliver for me.

I should start by saying, that I like Rails on a lot of areas. But we also know, that all technologies and tools have a flip side, which we come to know about only by using it for some time.

Let us jump right in...

1. Domain Modelling
A lot of the domain objects (though, by all means not all) of the domain model will come from representations of relational database tables. In Rails, these need to inherit ActiveRecord::Base, which is definitely polluting the domain model.

But what about behaviour only domain objects? One example is reporting queries and how to model them. Say I need to select some of the attributes of two joined tables Foo and Bar. One way to do it is to add a static finder method on one of them, say Foo (which one can be hard to choose). The finder will then return instances of the class chosen, Foo, but with a "nice" collection of attributes from the two different class types. Rails marks the instance as "readonly", but it really sucks. The model instance simple gets the attributes you select, even though they do not belong on the type. These are incomplete instances and not all domain logic will work on the model instance.

Actually, a lot seems to be hooked up on inheriting ActiveRecord::Base. There is no real is-a relation here between ActiveRecord::Base and the domain object.

2. Transaction Demarcation in Code
I knew this before entering Rails and I have come to hate it. You need to demarcate your transactions yourself in code. It is really not that nice.

3. Deployment
This is totally not as easy and clean as with Java. The sole existence (and need of) of a tool like Capistrano says it all. I have previously blogged about Rails deployment compared to Java and I think that post says it all.

4. Tool Support
Aahh, a much debated subject :-) I for one, can and have worked without nice tools, auto-completion and the like. But, I have also come to love what IDEA can do for me, when coding Java. This includes refactoring, auto-completion, documentation popup etc.

Now, this has changed a lot lately with tools like the IDEA Ruby plugin and NetBeans Ruby and Rails support. But still, there are stuff that is next to impossible to do, simply due to the dynamic nature of the Ruby language and the extensive use of these dynamic features in the Rails framework.

What makes NetBeans and IDEA plugins usable for more than syntax highlightning when doing Rails development is the fact, that they are targeting the Rails framework specificly. Not only the Ruby language.

5. Internationalization
It is not there. It is as simple as that. There are hacks and stuff out there, but in practise, it is missing from the framework.

6. Attributes of ActiveRecord models "Invisible"
Due to the dynamic nature of Rails, the attributes of ActiveRecord models are added dynamically by ActiveRecord, using a lookup of attributes on the database table. At first a nice thing with respect to speed in development. In the long term, I have found it irritating at best. I need to combine a view of a migration that created the table together with the model, to get the full picture. And even then, I am missing migrations that have added or changed the table.

And I am violating the DRY principle, when I am writing stuff like max length on a column and not null constraints in the migrations, but also needs to write the same in validations on the model.

7. Validations outside ActiveRecord
All the nice validations like validates_length_of or validates_uniqueness_of are tied to ActiveRecord. There are solutions out there to reuse this code in other classes, but it seems like a design error from the beginning.

8. Migrations Become a Pain
Talking about migrations. It quickly becomes unfeasible to use migrations to add extra columns or change an existing model. Often, migrations use the model classes to change the data as the schema changes. But, when running all migrations on a clean database, it is done using the latest and greatest version of the model. Not the version of the model when the migration was originally written.

9. Polluted APIs
Rails adds helper methods on various API classes which pollutes the APIs. But I suspect the Ruby APIs themselves to be quite polluted themselves. Try doing a "Date.methods" in the rails console: What the f*** are all those doing on Date? :-) If you could do completion in the IDE, you wouldn't be able to find the tree for the forrest

10. Documentation
The Rails framework documentation is spread all over the apidocs, which is not that good with respect to browsing it. I have found some cookbooks, wikis and other stuff, but there is a real lack of a good users manual and/or wiki controlled by some entity that can keep it together and updated.

So What Then?
Despite the above rants, I do like Rails. And I would also recommend it or use it myself, on some specific type of projects. These are the simple, CRUD-like ones with only a small amount of domain logic and complexity.

What I would love to do next time I startup a completely new project, is to base it on Java technologies this time, but choose them for what they have learnt from Rails. One example could be Tapestry5. Another could be Grails with GORM, but that might be too dynamic, hence experiencing the same problems. And then see how productivity is, while still retaining some of the Java goodies, like nice tool support, static checking, refactorings that works, completion, ...

Monday, October 01, 2007

Quicker Maven Builds

A simple tip. Maven builds quickly get slow, as more and more unit tests are added. Often, when developing, I do "maven -Dmaven.test.skip=true", until I think I am ready. I then do a build with tests and if okay, I commit.

Only thing is, typing "-Dmaven.test.skip=true" is long and tiring. But, you can shorten it down a bit. Add this to the profiles section of your settings.xml:

<profile>
<id>quick</id>
<properties>
<maven.test.skip>true</maven.test.skip>
</properties>
</profile>

Then, when you want to build without tests, you simply do "mvn -Pquick".

You can also do a little script or alias for quick building with maven, as I have previously written about.