Friday 4 December 2009

Apache Ivy - Working with the Apache tutorial

Apache Ivy is a dependancy manager and appears to be flavour of the month in some circles and claims to be less complicated than Maven.

Here is a quick tutorial that expands on Apaches tutorial page. They provide one very small build.xml in a style that they say is not best practise for a number of reasons:
  1. it is standalone
  2. it contains the code within the build.xml
  3. it downloads ivy locally instead of using a remote installation
I struggled to find a simple example of a build in the accepted syntax so I will attempt here to describe how this build.xml can be changed in 4 steps to ultimately work in the conventional style with a build.xml and ivy.xml files and a remote installation of ivy.

My next project will be to 'ivyfy' a spring project. Hopefully I will be successfull - watch this space.

prerequisites:
Apache Ant installed to 1.6 or greater

1) The basic Tutorial from Apache Ivy
  • Essentially follow their instructions & download the build.xml from the tutorial page
  • I had to edit the downloaded file to remove the dashes at the start of some lines
  • run 'ant'
  • I also changed the following line to refer to the latest formal release of ivy, but both will work.
from:
 <property name="ivy.install.version" value="2.0.0-beta1" /> 
to:
    <property name="ivy.install.version" value="2.1.0" />

2) Tutorial with no ivy
  • One of things about ivy is that you are supposed to take an existing project and 'ivyfy' - IE remove your local third party jars and rely on ivy to fullfill your dependancies
  • So this tutorial simply takes the results from the previous example and gets it to work without ivy.
  • It therefore needs the src folder & its contents, the commons-lang jar in a lib dir in the project and a build.xml
  • The file structure for this and future tutorials is:
.
./build.xml
./file
./filestructure
./lib
./lib/commons-lang-2.1.jar
./src
./src/example
./src/example/Hello.java
  • The build.xml required is:
<project name="go-ivy" default="go" >

<property name="build.dir" value="build" />
<property name="src.dir" value="src" />
<property name="lib.path.id" value="lib" />

<path id="compile.classpath">
<fileset dir="${lib.path.id}">
<include name="**/*.jar"/>
</fileset>
</path>

<!-- =================================
target: go Go ivy, go!
================================= -->
<target name="go" depends=""
description="--> resolve dependencies, compile and run the project">
<echo message="NOT using ivy to resolve commons-lang 2.1..."/>

<echo message="compiling..."/>
<mkdir dir="${build.dir}" />
<javac srcdir="${src.dir}" destdir="${build.dir}" >
<classpath refid="compile.classpath"/>
</javac>

<java classname="example.Hello">
<classpath>
<fileset dir="${lib.path.id}">
<include name="**/*.jar"/>
</fileset>
<path location="${build.dir}" />
</classpath>
</java>
</target>


<!-- =================================
target: clean
================================= -->
<target name="clean" description="--> clean the project">
<delete includeemptydirs="true" quiet="true">
<fileset dir="${src.dir}" />
<fileset dir="${build.dir}" />
</delete>
</target>
</project>

3) Tutorial with ivy.xml
  • In the above example everything is defined in the build.xml. The clever thing with ivy and maven is that your project does not explicitly contain third party jars.
  • Instead these are defined in a config file, ivy.xml in this case.
  • This step moves the dependancies defined in build.xml into a seperate ivy.xml
  • again simply run 'ant' to test.
  • For this and subsequent tutorials I did not generate the src files. I kept them from the first tutorial
  • Therefore for this and subsequent tutorials all you need is the src folder with the src file, the build.xml & ivy.xml
  • Here is the ivy.xml
<ivy-module version="2.0">
<info organisation="Utilisoft" module="Test-withivy.xml"/>
<dependencies>
<dependency org="commons-lang" name="commons-lang" rev="2.1"/>
</dependencies>
</ivy-module>
  • Here is the new build.xml - I have removed much of the comments to make it smaller.
<project name="go-ivy-with-ivy.xml" default="go" xmlns:ivy="antlib:org.apache.ivy.ant" basedir=".">
<!-- here is the version of ivy we will use. change this property to try a newer
version if you want -->
<property name="ivy.install.version" value="2.1.0" />
<property name="ivy.jar.dir" value="${basedir}/ivy" />
<property name="ivy.jar.file" value="${ivy.jar.dir}/ivy.jar" />

<property name = "ivy.lib.dir" value="${basedir}\newlib" />

<path id="lib.path.id">
<fileset dir="${ivy.lib.dir}" />
</path>

<property name="build.dir" value="build" />
<property name="src.dir" value="src" />

<!-- =================================
target: go Go ivy, go!
================================= -->
<target name="go" depends="resolve "
description="--> resolve dependencies, compile and run the project">
<echo message="using ivy to resolve commons-lang 2.1 with ivy.xml"/>

<echo message="compiling..."/>
<mkdir dir="${build.dir}" />
<javac srcdir="${src.dir}" destdir="${build.dir}" classpathref="lib.path.id" />

<java classname="example.Hello">
<classpath>
<path refid="lib.path.id" />
<path location="${build.dir}" />
</classpath>
</java>
</target>


<!-- =================================
target: clean
================================= -->
<target name="clean" description="--> clean the project">
<delete includeemptydirs="true" quiet="true">
<fileset dir="${src.dir}" />
<fileset dir="${build.dir}" />
</delete>
</target>

<target name="resolve" depends="install-ivy" description="Resolve the dependencies">
<ivy:retrieve/>
</target>


<!-- =================================
target: install-ivy
this target is not necessary if you put ivy.jar in your ant lib directory
if you already have ivy in your ant lib, you can simply remove this
target and the dependency the 'go' target has on it
================================= -->
<target name="install-ivy" depends="download-ivy" description="--> install ivy">
<!-- try to load ivy here from local ivy dir, in case the user has not already dropped
it into ant's lib dir (note that the latter copy will always take precedence).
We will not fail as long as local lib dir exists (it may be empty) and
ivy is in at least one of ant's lib dir or the local lib dir. -->
<path id="ivy.lib.path">
<fileset dir="${ivy.jar.dir}" includes="*.jar"/>
</path>
<taskdef resource="org/apache/ivy/ant/antlib.xml"
uri="antlib:org.apache.ivy.ant" classpathref="ivy.lib.path"/>
</target>

<target name="download-ivy" unless="skip.download">
<mkdir dir="${ivy.jar.dir}"/>
<!-- download Ivy from web site so that it can be used even without any special installation -->
<echo message="installing ivy..."/>
<get src="http://repo1.maven.org/maven2/org/apache/ivy/ivy/${ivy.install.version}/ivy-${ivy.install.version}.jar" dest="${ivy.jar.file}" usetimestamp="true"/>
</target>
</project>

4) Tutorial with remote Ivy
  • Hopefully you are still with me. This is the last step in this tutorial set.
  • The above example still downloads ivy locally
  • This example will now use ivy as part of your apache and installation
  • In the last example a ivy.jar file appeared in an 'ivy' directory.
  • Determine the location of your apache ant installation and copy this jar into the apache ant lib directory.
  • Ensure you have an ANT_HOME environment variable pointing to the apache4 ant installation directory
  • Below is the new build.xml file you will need.
<project name="go-ivy-with-ivy.xml" default="go" xmlns:ivy="antlib:org.apache.ivy.ant" basedir=".">
<!-- here is the version of ivy we will use. change this property to try a newer
version if you want -->
<property name="ivy.install.version" value="2.1.0" />
<property name="ivy.jar.dir" value="${basedir}/ivy" />
<property name="ivy.jar.file" value="${ivy.jar.dir}/ivy.jar" />

<property name = "ivy.lib.dir" value="${basedir}\newlib" />

<path id="lib.path.id">
<fileset dir="${ivy.lib.dir}" />
</path>

<property name="build.dir" value="build" />
<property name="src.dir" value="src" />

<!-- =================================
target: go
Go ivy, go!
================================= -->
<target name="go" depends="resolve "
description="--> resolve dependencies, compile and run the project">
<echo message="using ivy to resolve commons-lang 2.1 with ivy.xml"/>

<echo message="compiling..."/>
<mkdir dir="${build.dir}" />
<javac srcdir="${src.dir}" destdir="${build.dir}" classpathref="lib.path.id" />

<echo>
We are now ready to execute our simple program with its dependency on commons-lang.
Let's go!
</echo>
<java classname="example.Hello">
<classpath>
<path refid="lib.path.id" />
<path location="${build.dir}" />
</classpath>
</java>
</target>

<!-- =================================
target: clean
================================= -->
<target name="clean" description="--> clean the project">
<delete includeemptydirs="true" quiet="true">
<fileset dir="${src.dir}" />
<fileset dir="${build.dir}" />
</delete>
</target>

<target name="resolve" depends="" description="Resolve the dependencies">
<ivy:retrieve/>
</target>
</project>

And to the future. I have two immediate aims:
  1. Get a build of a spring hibernate using Ivy
  2. Get a project with dependant projects using spring and hibernate using ivy.

Tuesday 1 December 2009

oracle - listing all tables in a schema

select table_name,
to_number( extractvalue( xmltype(
dbms_xmlgen.getxml('select count(*) c from '||table_name))
,'/ROWSET/ROW/C')) count
from user_tables;

courtesy of Burleson

Monday 23 November 2009

SQL info for oracle/sqlserver/mysql

While performing some testing to ensure my app was compliant with multiple db flavours I came across this site.

It is a useful reference to quickly see how the different flavours perform some common operations.

Friday 6 November 2009

humax PVRs and the digital switch over

I have two Humax PVR freeview recorders that have been running quite happily for several years.

The 4th November was our official DSO date for the north west and suddenly most of my BBC channels had gone.

My two PVRs are a new 9300T and an aging 8000T.

A retune on the 9300 brought BBC back but with BBC1 on channel 800. The 8000T could not find BBC anywhere.

The fix for the 9300 was to go to the Installation Menu, select the 'Default Setting' menu, enter the pin code and reset the box. Low and behold BBC1 was back on channel 1.

However the 8000 was proving more awkward. For this box I performed a software update request from tyhe system menu. Despite not saying that any of the versions had changed this fixed the problem and BBC1 is now back on channel 1.

In parrallel I did email humax on UKSupport@humax-digital.co.uk and congratulations to them I did get a very prompt reply but I had fixed the problem by the time I had read the email. For interest they said to do the following:

Please follow the steps below to perform a Default reset;

1. Power OFF the receiver

2. Disconnect the Aerial cable

3. Power On the receiver

4. Press MENU

5. Select Installation

6. Enter your password (default = 0000)

7. Select Default Setting

8. Select YES

9. Enter your password (Default = 0000)

10. When the receiver restarts, power off

11. Connect the Aerial Cable

12. Power ON - the receiver will then search for the channels.

Thursday 23 July 2009

Eclipse, workspaces and JREs

Be aware that installed JREs are workspace specific.

IE. Your default JRE might be the MyEclipse 6.0.
You install and add Java 1.5 JRE and make this your default.

Then three months later you create a new workspace.
Low and behold this new workspace does not know about the 1.5 JRE.

Sunday 12 July 2009

Manchester to Blackpool bike ride

Just a quiet shout out for my eldest son Ben who rode and completed the Manchester to Blackpool bike ride today, all 60 miles at the ge of 11, raising money for Marie Curie, £150 so far.

He is feeling a tad tired tonight.

Awesome Ben - well done.

If you happen to read this please donate.

Friday 10 July 2009

EasyMock - Reason to update to the latest version

I have recently started working on a new project that consisted of three dependant Java projects.

These three projects were using two different versions of EasyMock so first off I decided to bring them into line. The projects are all Java5 but one project had EasyMock 2.4 and the other two had EasyMock 1.3

Following on from Andrew Beacock's article on using easy mock's class extensions I decided to give that a go.

Strangely after upgrading some of the tests were failing. Why ?

Well it looks to me like a bug in the old version of EasyMock 1.3,
so the easy answer is upgrade. The bug appears to be that you can not call MockControl.expectAndDefaultReturn() more than once.

Here is the test using the old code, and below that a test class using 2.4.

EasyMock 1.3 version:
package uk.co.utilisoft.entrecaweb.web.validators;

import java.util.ArrayList;
import java.util.List;

import junit.framework.TestCase;

import org.easymock.MockControl;

public class TryOldEasyMock extends TestCase{

public void testSingleCall(){
List<String> list = new ArrayList<String>();
list.add("hello");
MockControl control = MockControl.createControl(TestMock1.class);
TestMock1 mock = (TestMock1)control.getMock();

ClassUnderTest1 classUnderTest = new ClassUnderTest1();
classUnderTest.setService(mock);

control.expectAndDefaultReturn(mock.getLength("hello"), 5);
control.replay();
assertEquals(5, classUnderTest.getLength(list));
control.verify();
}


public void testTwoCalls(){
List<String> list = new ArrayList<String>();
list.add("hello");
list.add("bye");

MockControl control = MockControl.createControl(TestMock1.class);
TestMock1 mock = (TestMock1)control.getMock();

ClassUnderTest1 classUnderTest = new ClassUnderTest1();
classUnderTest.setService(mock);

control.expectAndDefaultReturn(mock.getLength("hello"), 5);
control.expectAndDefaultReturn(mock.getLength("bye"), 95);
control.replay();


assertEquals("this is the wrong value & should fail.", 190, classUnderTest.getLength(list));
assertEquals("this is the correct value & should pass.", 100, classUnderTest.getLength(list));
control.verify();
}
}

class ClassUnderTest1{
private TestMock1 service;

public void setService(TestMock1 service) {
this.service = service;
}

public int getLength(List<String> someText)
{
int total = 0;
for (String value : someText) {
total += service.getLength(value);
}
return total;
}

}

interface TestMock1
{
public int getLength(String someText);
}


EasyMock 2.4 version, using the class extensions jar:
package uk.co.utilisoft.entrecaweb.web.validators;

import java.util.ArrayList;
import java.util.List;

import junit.framework.TestCase;
import static org.easymock.classextension.EasyMock.*;

public class TryEasyMockTest extends TestCase {

public void testSingleCall()
{
List<String> list = new ArrayList<String>();
list.add("hello");

TestMock mock = createMock(TestMock.class);

expect(mock.getLength("hello")).andReturn(5);

ClassUnderTest classUnderTest = new ClassUnderTest();
classUnderTest.setService(mock);
replay(mock);

assertEquals(5, classUnderTest.getLength(list));
verify(mock);
}

public void testTwoCalls()
{
List<String> list = new ArrayList<String>();
list.add("hello");
list.add("bye");

TestMock mock = createMock(TestMock.class);

expect(mock.getLength("hello")).andReturn(5);
expect(mock.getLength("bye")).andReturn(95);

ClassUnderTest classUnderTest = new ClassUnderTest();
classUnderTest.setService(mock);
replay(mock);

assertEquals(100, classUnderTest.getLength(list));
verify(mock);
}
}

class ClassUnderTest{
private TestMock service;

public void setService(TestMock service) {
this.service = service;
}

public int getLength(List<String> someText)
{
int total = 0;
for (String value : someText) {
total += service.getLength(value);
}
return total;
}

}

class TestMock
{
public int getLength(String someText){
return someText.length();
}
}

Wednesday 8 July 2009

Testing Times - Freezing Times

I have found many tests that want to set a time in a class and then test that that object has the correct time set.

Often these tests will pass when run locally as unit tests but either fail as integration tests which tend to be slower or fail when run on a heavily loaded build server.

I came across the solution on Mark Needham's Blog making use of a joda-time.

There appears to be may other usefull classes such as LocalDate, a class that just holds the date, yep the bit that says 25/12/2009 with no time representation, ie just a date !!!

Monday 15 June 2009

Eclipse - java.lang.RuntimeException unable to get class information for @throws tag for SomeException

Working in Eclipse, I had a previously working project that I had closed.

After reopening it I found it was littered with apparent errors,
that were not there before.

Somehow checkstyle had got confused. Simply turning checkstyle off and back on again removed all the errors.

Tuesday 19 May 2009

DbUnit and nullable columns

We use DbUnit for our database integration tests and this works very well allowing us to populate the database with test data specific for the test at hand.

I have had a problem for the last few hours that has driven me to distraction. I was populating a table with a row and the tests using this data were all OK.

I then added an extra row that also wanted to populate an extra nullable column. The test failed because the test thought this column was null. I stopped the test in the debugger and yes the code was correct, the column was null. What could be wrong ?

My DbUnit XML looked like this:
<dataset>
<MY_TABLE
ID="1"
MANDATORY_COL="This column must have data"
/>

<MY_TABLE
ID="2"
MANDATORY_COL="This column must have data"
NULLABLE_COL="This column is nullable"
/>
</dataset>


The problem appears to be that DbUnit builds its list of columns from the first occurrance of each table. Any optional columns listed in subsequent entries are simply ignored.

There are two solutions. Either reverse the order of the two items in the XML file, or set the column to null in the rows where the nullable column is not required.

Friday 15 May 2009

TDD Testing of Dependancy Injection in Spring

Spring relies very heavily on dependancy injection and when writing integration tests the first thing that must work before you even try to connect to things like your database is that all your beans must be correctly injected.

So before I get all excited and start writing tests that read or write to the database I write a very simple test to check that everything has been injected correctly.

public class FooServiceIntegrationTest extends BaseIntegrationTester{
private FooService fooService;

public void setFooService(BulkUploadService aFooService){
fooService = aFooService;
}

public void testInjection() throws Exception{
assertNotNull("FooService not injected", fooService);
}
}

Strictly speaking this test testInjection is not needed at this stage because the test will fail if the injection of this primary bean fails.

Ok so I need to create the bean.

<bean id="fooService" name="fooService" class="uk.co.foo.FooServiceImpl">
</bean>

The test will now pass.

The test now gets more useful as I now extend the test to see if FooService has its beans injected successfully.

public class FooServiceIntegrationTest extends BaseIntegrationTester{
private FooService fooService;

public void setFooService(BulkUploadService aFooService){
fooService = aFooService;
}

public void testInjection() throws Exception{
assertNotNull("FooService not injected", fooService);
assertNotNull("FooService not injected", fooService.getBarDao());
}
}

Now this will not compile at first as fooService.getBarDao() does not exist.
I add this to the interface and implement the method and re-run the test,

The test fails as we have not set the property on the bean so lets do that.

<bean id="fooService" name="fooService" class="uk.co.foo.FooServiceImpl">
<property name="barDao" ref="barDao" />
</bean>

Assuming barDao has also been configured then the test will now pass.

Possibly others do this, I do not know but I have found this little test invaluable as a precursor to grander integration tests later on.

BTW BaseIntegration tester does little more than extend AbstractTransactionalDataSourceSpringContextTests and implement the method getConfigLocations()

Thursday 14 May 2009

Eclipse Hot Keys and the language bar on Windows

I like to use Eclipse Hot Keys and two of my favourites are Ctrl+Shift+R (open a resource) and the very similar Ctrl+Shift+T.

Sometimes when in eclipse I would do something and suddenly find the double quote and '@' keys (among others) had swopped.

I sussed out that somehow I was changing my keyboard settings from English UK to English US. I left it at that now I knew I could fix it.

Today I sussed out why and how to stop it happening again.

The hot keys to change the language is Ctrl+Shift and I must have been missing off the R or T.

So assuming you do not want to change the keyboard from one to the other at all or not too often you have two options:
a) disable the hot keys
b) remove the language you do not want.

To do this go to: Contol Panel->Regional & Language options->Languages->Details.

If you want to disable the hot keys select Key Settings->'Change Key Sequence'.
If you want to remove one of the languages, select one and then select 'remove'

Thursday 9 April 2009

Spring User Group in the North West

Last night was the inaugrial North West Spring User Group.

There were two speakers, Jan Machacek of Cake Solutions and a joint author of Pro Spring 2.5 and Rob Harrop from SpringSource and also joint author with Jan on the original 'Pro Spring' book

Jan gave an excellent worked example of a small web application using Spring 3.0 and Rob also ran a worked example on REST development in Spring. Rob's talk was particularly interesting and brave in that he was willing to show the REST development at the cutting edge and show and admit to its weaknesses with it being only at milestone release.

There will be future meetings and you can follow them at the Linkedin User group

Tuesday 24 March 2009

KeePass - Secure password and data storage

For a while I have wanted some form of secure password and data storage and I came across KeePass.

This tool appears to do everything I want.

I can run it standalone from a USB device without installing any software or registry changes on the PC.

I can store passwords as well as custom information.

There is a wealth of plugins for things like backups and browser integration.

And its free.

Tuesday 17 March 2009

org.hibernate.DuplicateMappingException and tomcat

There are probably many reasons why you might get a DuplicateMappingException from an application using hibernate. Not least because you have a mapping defined twice.

However I have just found this reason and it is new to me.

In the tomcat logs I found this:
Caused by: org.hibernate.DuplicateMappingException: Duplicate class/entity mapping uk.co.formfill.dfcommon.domain.dfwv.Action
at org.hibernate.cfg.Mappings.addClass(Mappings.java:118)
at org.hibernate.cfg.HbmBinder.bindRoot(HbmBinder.java:154)
at org.hibernate.cfg.Configuration.add(Configuration.java:386)
at org.hibernate.cfg.Configuration.addInputStream(Configuration.java:427)
at org.hibernate.cfg.Configuration.addFile(Configuration.java:267)

Looking further up the tomcat logs to just before the first Exception stack trace there was this:
17-03-2009 10:44:22 [Thread-1] INFO  - Reading mappings from file: D:\apache-tomcat-6.0.14\work\Catalina\localhost\dfweb\loader\uk\co\formfill\dfcommon\hibernate\mappings\dfwv\actions.hbm.xml
17-03-2009 10:44:22 [Thread-1] INFO - duplicate import: uk.co.formfill.dfcommon.domain.dfwv.Action->uk.co.formfill.dfcommon.domain.dfwv.Action
17-03-2009 10:44:22 [Thread-1] INFO - duplicate import: uk.co.formfill.dfcommon.domain.dfwv.Action->Action
17-03-2009 10:44:22 [Thread-1] INFO - Mapping class: uk.co.formfill.dfcommon.domain.dfwv.Action -> ACTIONS

So I looked in D:\apache-tomcat-6.0.14\work\Catalina\localhost\dfweb and that was empty. Strange.

The same war worked fine on a different installation and the cause was in the tomcat configuration.

The offending line was in tomcat's context.xml with the problem being the overriding of the antiJARLocking property which had been done beacuse of some historical apps..
<Context antiJARLocking="true">

Removing this and all is fine. Looking at the tomcat documentation I can not see why this problem might occurr but hey ho, it is fixed.

Thursday 26 February 2009

Pretty printing Java classpaths using Ant's pathconvert task

This is a blatent reproduction from a friend of mines blog Andrew Beacock for two reasons.

1. I can never find it.
2. A kind sole by the name of Remke provided a very nice enhancement using a macro

Here is the echopath macro


<!-- = = = = = = = = = = = = = = = = =
macrodef: echopath
= = = = = = = = = = = = = = = = = -->
<macrodef name="echopath">
<attribute name="pathid" />
<sequential>
<property name="line.pathprefix" value="| |-- " />
<!-- get given path in a printable form -->
<pathconvert pathsep="${line.separator}${line.pathprefix}"
property="echo.@{pathid}" refid="@{pathid}">
</pathconvert>
<echo>
Path @{pathid}
${line.pathprefix}${echo.@{pathid}}
</echo>
</sequential>
</macrodef>


Call the macro like this:
<path id="quick_test_classpath">
<path refid="test.classpath" />
<pathelement location="${instrumented.classes.dir.dev}"/>
<pathelement location ="${classes.dir.dev}" />
<pathelement location ="${test.config.dir.dev}" />
<pathelement location ="${dfcommon.dir.dev}" />
</path>

<target name="display_my_classpath" >
<echopath pathid="quick_test_classpath"/>
</target>


This will produce some output like:
[echo]
[echo] Path quick_test_classpath
[echo] | |-- C:\projects\foo\bar\test\lib\ant-junit.jar
[echo] | |-- C:\projects\foo\bar\test\lib\dbunit-2.3.0.jar
[echo] | |-- C:\projects\foo\bar\WebRoot\WEB-INF\lib\commons-beanutils.jar
[echo] | |-- C:\projects\foo\bar\WebRoot\WEB-INF\lib\commons-codec-1.3.jar
[echo] | |-- C:\projects\foo\bar\WebRoot\WEB-INF\lib\commons-collections-3.2.1.jar
[echo] | |-- C:\projects\foo\bar\WebRoot\WEB-INF\lib\commons-dbcp-1.2.1.jar
[echo]


Andrew's original bog post can be found here

Thursday 29 January 2009

NTLM Authentication and the IE Post Problem

We are using NTLM Windows Authentication for a Single Sign On (SSO) project.

We are using the Spring security Filter NtlmProcessingFilter which for most of the time is absolutely fine.

However the are atleast two scenarios where this fails.

1) When the session is timed out and a form.submit() request is made.
Under this situation a windows logon box is presented. This is obviously not desirable in a SSO project.

2) If the page makes heavy use of dwr/javascript.
In this case the page makes repeated NTLM authentication requests and stack traces are observed with the message 'This is not a Type 3 Message'.

There is a solution described in the jcifs documentation. Search for registry key. This solution works but is not suitable for us as our client would not let us change the registry on all the client PCs. Quite understandably I think.

The fix described here applies to Spring-Security 2.0.4 and jcifs 1.2.25 but is also required for jcifs to atleast 1.3.3

Both Spring-Security and jcifs have an NTLMFilter and it is to this that the fix is required.

Here is the Spring solution to org.springframework.security.ui.ntlm.NtlmProcessingFilter:


protected void doFilterHttp(final HttpServletRequest request,
final HttpServletResponse response, final FilterChain chain)
throws IOException, ServletException {
final HttpSession session = request.getSession();
Integer ntlmState = (Integer) session.getAttribute(STATE_ATTR);

final String authMessage = request.getHeader("Authorization");

// Check the special IE POST request with Authorization header containing
// type-1 message (see method javadoc)
if (this.reAuthOnIEPost(request)) {
if ((authMessage != null) && (authMessage.startsWith("NTLM "))) {
logger.debug("POST Request with NTLM Authorization detected.");
// decode the NTLM response from the client
byte[] src = Base64.decode(authMessage.substring(5));
// see if a type 1 message was sent by the client
if (src[8] == 1) {
logger
.debug("NTLM Authorization header contains type-1 message. Sending fake response just to pass this stage...");
Type1Message type1 = new Type1Message(src);
// respond with a type 2 message, where the challenge is null since we
// don't
// care about the server response (type-3 message) since we're already
// authenticated
// (This is just a by-pass - see method javadoc)
Type2Message type2 = new Type2Message(type1, new byte[8], null);
String msg = Base64.encode(type2.toByteArray());
response.setHeader("WWW-Authenticate", "NTLM " + msg);
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.setContentLength(0);
response.flushBuffer();
}
}
} else {
..... existing filter code
}
chain.doFilter(request, response);
}

The fix for jcifs appears to be very similar and thanks to Asaf Mesika off the jcifs forum for his help. NB: I have not tried this jcifs solution. For jcifs the fix is to jcifs.http.NtlmHttpFilter:


protected NtlmPasswordAuthentication negotiate( HttpServletRequest req,
HttpServletResponse resp,
boolean skipAuthentication ) throws IOException, ServletException {
UniAddress dc;
String msg;
NtlmPasswordAuthentication ntlm = null;
msg = req.getHeader( "Authorization" );
boolean offerBasic = enableBasic && (insecureBasic || req.isSecure());

// Check the special POST request with Authorization header containing type-1 message (see method javadoc)
if (request.getMethod().equalsIgnoreCase("POST")) {
String authorization = request.getHeader( "Authorization" );
if ( (authorization != null) && (authorization.startsWith("NTLM ")) ) {
logger.debug("POST Request with NTLM Authorization detected.");
// decode the NTLM response from the client
byte[] src = Base64.decode(authorization.substring(5));
// see if a type 1 message was sent by the client
if (src[8] == 1) {
logger.debug("NTLM Authorization header contains type-1 message. Sending fake response just to pass this stage...");
Type1Message type1 = new Type1Message(src);
// respond with a type 2 message, where the challenge is null since we don't
// care about the server response (type-3 message) since we're already authenticated
// (This is just a by-pass - see method javadoc)
Type2Message type2 = new Type2Message(type1, new byte[8], null);
String msg = Base64.encode(type2.toByteArray());
response.setHeader("WWW-Authenticate", "NTLM " + msg);
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.setContentLength(0);
response.flushBuffer();
return false;
}
}
}

... existing filter code ....
}

I have raised a spring-security bug if you want to see if it is fixed in the version you have.

Wednesday 7 January 2009

Garmin Forerunner - Pairing extra devices

With my new Garmin Forerunner 50 I also got the GSC 10 cycle speed & cadence sensor.

I really struggled to pair this extra device. I followed the instructions, changed batteries etc with no luck. It flatly refused to see the sensor.

After much hunting I discoverred the Garmin FAQ. This said to try riding the bike at the same time. IE wake up the sensor while pairing is happening.

A simpler solution was to wave the magnet near the sensor. Bingo. it is now all paired up.

Garmin Forerunner ANT Agent and running XP exe's on Vista

Lucky me, I received a Garmin Forerunner 50 heart rate monitor for christmas.

Incidently it was bought off amazon which is selling it an an amazing price.

The Forerunner series have the excellent capability of uploading your heart and distance data to garmin.com.

This is done by a wireless dongle and some software called ANT Agent. However this is an Windows XP executable and would not run. Many people appear to have struggled with this but the solution is quite easy and I found how here. This is presumably true for many other XP executables.

In case the link does not work this is what you have to do:
1. right click the ANT Agent executable you have just downloaded.
2. choose Properties
3. Navigate to the Compatibility tab
4. Set the Compatibility mode to Windows XP (Service Pack 2)
5. Click OK to save the settings
6. Run the exe and all should be OK