You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@cxf.apache.org by Daniel Kulp <dk...@apache.org> on 2009/06/02 04:49:10 UTC

Re: Exception with JaxWsClientProxy when invoking a method with complex objects

>
> Bug or feature?

Bug

Thanks for the information.  I was able to reproduce the issue.   Found a 
bunch of other issues while debugging it as well.     Fix is now committed to 
trunk.  Should be in tomorrows snapshots.

Thanks!
Dan


On Thu May 28 2009 8:02:28 am Bruno Aranda wrote:
> Hi,
>
> I couldn't investigate this issue until today, but I found the reason
> to this problem.
>
> Basically I am generating my classes from the WSDL using the
> cxf-codegen-plugin. In my jaxb bindings I was using <xjc:simple> to
> generate nice method names for the generated classes.
>
> However, changing the methods names did affect the ability to choose
> the correct accessors in the org.apache.cxf.jaxb.JAXBUtils class.
>
> For example, I had a list of a complex some object called "dbRef":
>
>          <xs:complexType name="dbRefListRequest">
>                 <xs:sequence>
>                     <xs:element name="dbRefList" type="psq:dbRefList"/>
>                 </xs:sequence>
>             </xs:complexType>
>
>             <xs:complexType name="dbRefList">
>                 <xs:sequence>
>                     <xs:element maxOccurs="unbounded" name="dbRef"
> type="psq:dbRef"/>
>                 </xs:sequence>
>             </xs:complexType>
>
> The generator was creating a class that used this list, where the
> accessor methods had the funny name "getDbReves" or "setDbReves" (of
> couse, the plural of dbRef is dbReves? :))
>
> @XmlAccessorType(XmlAccessType.FIELD)
> @XmlType(name = "getByInteractionList", propOrder = {
>     "dbReves",
>     "infoRequest"
> })
> public class GetByInteractionList {
>
>     @XmlElement(name="dbRef", required = true)
>     protected List<DbRef> dbReves;
>
> ...
>
> And then those accessors were not found.
>
> Removing the <xjc:simple> fixes the issue, but I have lost the "nice"
> plurals, which I can live with.
>
> Bug or feature?
>
> Thanks,
>
> Bruno
>
> 2009/4/20 Bruno Aranda <br...@gmail.com>:
> > Hi,
> >
> > Yes, other methods like the one you propose works. I have an very similar
> > method that instead of the list of DbRef accepts just a DbRef and that
> > one works. I will try to debug it further and to create a simple test
> > case if I can...
> >
> > Thanks,
> >
> > Bruno
> >
> > 2009/4/20 Daniel Kulp <dk...@apache.org>
> >
> >> The list should work fine as long as the thing it is a list of also
> >> works fine.    Are there any annotations on DbRef?   The issue really
> >> comes down to
> >> why is the typeQName null in this case.    It should definitely not be.
> >>
> >> Does a method like:
> >>
> >> int testDbRef(DbRef ref)
> >>
> >> work?
> >>
> >> Any chance you could create a small sample and attach to a JIRA?
> >>
> >> Dan
> >>
> >> On Mon April 20 2009 5:27:49 am Bruno Aranda wrote:
> >> > Hi, sorry to write again, but I have more details about the problem:
> >> >
> >> > The method signature:
> >> >
> >> > QueryResponse getByInteractorList( List<DbRef> dbRef, RequestInfo
> >> > infoRequest, String operand );
> >> >
> >> > QueryResponse, DbRef and RequestInfo are complex objects. The problem
> >> > seems
> >> > to be related to the use of the List<DbRef> parameter. In the line
> >> > where the exception below happens, the first item of an array called
> >> > getMethods[]
> >> > is being invoked (getMethods[0]). However, this array does not seem
> >> > anything set in position 0 (but there are values for getMethods[1] and
> >> > getMethods[2]). So getMethods[0] returns null, hence the
> >> > NullPointerException.
> >> >
> >> > I see that in
> >> > org.apache.cxf.jaxws.interceptors.WrapperClassOutInterceptor
> >> > (line 161) the element type is set to null because the message part
> >> > does not have a typeQName. This null is the one causing the NPE later
> >> > on,
> >> >
> >> > Any ideas? Aren't List object allowed as parameters?
> >> >
> >> > Thank you,
> >> >
> >> > Bruno
> >> >
> >> >
> >> >
> >> > 2009/4/20 Bruno Aranda <br...@gmail.com>
> >> >
> >> > > Hi,
> >> > >
> >> > > Many thanks for your answer. I have tried with 2.2.1-SNAPSHOT but it
> >> > > didn't work either. However, I have the exception cause now. That
> >> > > this make sense to anyone? How can I avoid this NPE?
> >> > >
> >> > > java.lang.NullPointerException
> >> > >     at
> >> > >
> >> > > org.apache.cxf.databinding.AbstractWrapperHelper.createWrapperObject
> >> > >(Abst ractWrapperHelper.java:86) at
> >> > >
> >> > > org.apache.cxf.jaxws.interceptors.WrapperClassOutInterceptor.handleM
> >> > >essag e(WrapperClassOutInterceptor.java:103) at
> >> > >
> >> > > org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseIntercep
> >> > >torCh ain.java:236) at
> >> > > org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:469) at
> >> > > org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:299) at
> >> > > org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:251) at
> >> > > org.apache.cxf.frontend.ClientProxy.invokeSync(ClientProxy.java:73)
> >> > > at
> >> > >
> >> > > org.apache.cxf.jaxws.JaxWsClientProxy.invoke(JaxWsClientProxy.java:1
> >> > >20) at $Proxy62.getByInteractorList(Unknown Source)
> >> > >     at
> >> > >
> >> > > uk.ac.ebi.intact.psicquic.wsclient.MitabPsicquicClient.getByInteract
> >> > >orLis t(MitabPsicquicClient.java:104) at
> >> > >
> >> > > uk.ac.ebi.intact.psicquic.wsclient.MitabPsicquicClientTest.client(Mi
> >> > >tabPs icquicClientTest.java:37) at
> >> > > sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at
> >> > >
> >> > > sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl
> >> > >.java
> >> > >
> >> > >:39) at
> >> > >
> >> > > sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAcce
> >> > >ssorI mpl.java:25) at
> >> > > java.lang.reflect.Method.invoke(Method.java:585) at
> >> > >
> >> > > org.junit.internal.runners.TestMethodRunner.executeMethodBody(TestMe
> >> > >thodR unner.java:99) at
> >> > >
> >> > > org.junit.internal.runners.TestMethodRunner.runUnprotected(TestMetho
> >> > >dRunn er.java:81) at
> >> > >
> >> > > org.junit.internal.runners.BeforeAndAfterRunner.runProtected(BeforeA
> >> > >ndAft erRunner.java:34) at
> >> > >
> >> > > org.junit.internal.runners.TestMethodRunner.runMethod(TestMethodRunn
> >> > >er.ja va:75) at
> >> > >
> >> > > org.junit.internal.runners.TestMethodRunner.run(TestMethodRunner.jav
> >> > >a:45) at
> >> > >
> >> > > org.junit.internal.runners.TestClassMethodsRunner.invokeTestMethod(T
> >> > >estCl assMethodsRunner.java:75) at
> >> > >
> >> > > org.junit.internal.runners.TestClassMethodsRunner.run(TestClassMetho
> >> > >dsRun ner.java:36) at
> >> > >
> >> > > org.junit.internal.runners.TestClassRunner$1.runUnprotected(TestClas
> >> > >sRunn er.java:42) at
> >> > >
> >> > > org.junit.internal.runners.BeforeAndAfterRunner.runProtected(BeforeA
> >> > >ndAft erRunner.java:34) at
> >> > >
> >> > > org.junit.internal.runners.TestClassRunner.run(TestClassRunner.java:
> >> > >52) at
> >> > >
> >> > > com.intellij.rt.junit4.Junit4TestMethodAdapter.run(Junit4TestMethodA
> >> > >dapte r.java:62) at
> >> > > junit.textui.TestRunner.doRun(TestRunner.java:116) at
> >> > >
> >> > > com.intellij.rt.execution.junit.IdeaTestRunner.doRun(IdeaTestRunner.
> >> > >java: 94) at junit.textui.TestRunner.doRun(TestRunner.java:109)
> >> > >     at
> >> > >
> >> > > com.intellij.rt.execution.junit.IdeaTestRunner.startRunnerWithArgs(I
> >> > >deaTe stRunner.java:22) at
> >> > >
> >> > > com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(
> >> > >JUnit Starter.java:118) at
> >> > >
> >> > > com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:
> >> > >40) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at
> >> > >
> >> > > sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl
> >> > >.java
> >> > >
> >> > >:39) at
> >> > >
> >> > > sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAcce
> >> > >ssorI mpl.java:25) at
> >> > > java.lang.reflect.Method.invoke(Method.java:585) at
> >> > > com.intellij.rt.execution.application.AppMain.main(AppMain.java:90)
> >> > > Apr
> >> > > 20, 2009 9:28:40 AM org.apache.cxf.phase.PhaseInterceptorChain
> >> > > doIntercept
> >> > > INFO: Interceptor has thrown exception, unwinding now
> >> > > org.apache.cxf.interceptor.Fault
> >> > >     at
> >> > >
> >> > > org.apache.cxf.databinding.AbstractWrapperHelper.createWrapperObject
> >> > >(Abst ractWrapperHelper.java:107) at
> >> > >
> >> > > org.apache.cxf.jaxws.interceptors.WrapperClassOutInterceptor.handleM
> >> > >essag e(WrapperClassOutInterceptor.java:103) at
> >> > >
> >> > > org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseIntercep
> >> > >torCh ain.java:236) at
> >> > > org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:469) at
> >> > > org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:299) at
> >> > > org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:251) at
> >> > > org.apache.cxf.frontend.ClientProxy.invokeSync(ClientProxy.java:73)
> >> > > at
> >> > >
> >> > > org.apache.cxf.jaxws.JaxWsClientProxy.invoke(JaxWsClientProxy.java:1
> >> > >20) at $Proxy62.getByInteractorList(Unknown Source)
> >> > >     at
> >> > >
> >> > > uk.ac.ebi.intact.psicquic.wsclient.MitabPsicquicClient.getByInteract
> >> > >orLis t(MitabPsicquicClient.java:104) at
> >> > >
> >> > > uk.ac.ebi.intact.psicquic.wsclient.MitabPsicquicClientTest.client(Mi
> >> > >tabPs icquicClientTest.java:37) at
> >> > > sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at
> >> > >
> >> > > sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl
> >> > >.java
> >> > >
> >> > >:39) at
> >> > >
> >> > > sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAcce
> >> > >ssorI mpl.java:25) at
> >> > > java.lang.reflect.Method.invoke(Method.java:585) at
> >> > >
> >> > > org.junit.internal.runners.TestMethodRunner.executeMethodBody(TestMe
> >> > >thodR unner.java:99) at
> >> > >
> >> > > org.junit.internal.runners.TestMethodRunner.runUnprotected(TestMetho
> >> > >dRunn er.java:81) at
> >> > >
> >> > > org.junit.internal.runners.BeforeAndAfterRunner.runProtected(BeforeA
> >> > >ndAft erRunner.java:34) at
> >> > >
> >> > > org.junit.internal.runners.TestMethodRunner.runMethod(TestMethodRunn
> >> > >er.ja va:75) at
> >> > >
> >> > > org.junit.internal.runners.TestMethodRunner.run(TestMethodRunner.jav
> >> > >a:45) at
> >> > >
> >> > > org.junit.internal.runners.TestClassMethodsRunner.invokeTestMethod(T
> >> > >estCl assMethodsRunner.java:75) at
> >> > >
> >> > > org.junit.internal.runners.TestClassMethodsRunner.run(TestClassMetho
> >> > >dsRun ner.java:36) at
> >> > >
> >> > > org.junit.internal.runners.TestClassRunner$1.runUnprotected(TestClas
> >> > >sRunn er.java:42) at
> >> > >
> >> > > org.junit.internal.runners.BeforeAndAfterRunner.runProtected(BeforeA
> >> > >ndAft erRunner.java:34) at
> >> > >
> >> > > org.junit.internal.runners.TestClassRunner.run(TestClassRunner.java:
> >> > >52) at
> >> > >
> >> > > com.intellij.rt.junit4.Junit4TestMethodAdapter.run(Junit4TestMethodA
> >> > >dapte r.java:62) at
> >> > > junit.textui.TestRunner.doRun(TestRunner.java:116) at
> >> > >
> >> > > com.intellij.rt.execution.junit.IdeaTestRunner.doRun(IdeaTestRunner.
> >> > >java: 94) at junit.textui.TestRunner.doRun(TestRunner.java:109)
> >> > >     at
> >> > >
> >> > > com.intellij.rt.execution.junit.IdeaTestRunner.startRunnerWithArgs(I
> >> > >deaTe stRunner.java:22) at
> >> > >
> >> > > com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(
> >> > >JUnit Starter.java:118) at
> >> > >
> >> > > com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:
> >> > >40) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at
> >> > >
> >> > > sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl
> >> > >.java
> >> > >
> >> > >:39) at
> >> > >
> >> > > sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAcce
> >> > >ssorI mpl.java:25) at
> >> > > java.lang.reflect.Method.invoke(Method.java:585) at
> >> > > com.intellij.rt.execution.application.AppMain.main(AppMain.java:90)
> >> > >
> >> > > Thanks,
> >> > >
> >> > > Bruno
> >> > >
> >> > > 2009/4/16 Daniel Kulp <dk...@apache.org>
> >> > >
> >> > >> Hmm...  not a useful stack trace.  Looks like we're wrappering a
> >> > >> Fault
> >> > >> with
> >> > >> another Fault  and the cause of that fault is "off the end" of your
> >> > >> trace.
> >> > >>
> >> > >> :-(
> >> > >>
> >> > >> Any chance you could catch the fault and dig into the causes and
> >> > >> get those stack traces?
> >> > >>
> >> > >> That said, I see:
> >> > >> WrapperHelper$ReflectWrapperHelper.
> >> > >> which USUALLY means that asm wasn't found on the classpath (or a
> >> > >> 1.x version
> >> > >> of asm was found, we need 2.x or 3.x).   You MAY be able to add asm
> >> > >> which should flip it over to a non-reflection based wrapper helper.
> >> > >> Maybe the bug
> >> > >> doesn't exist in that version.
> >> > >>
> >> > >> However, I'd still like to see the stack trace to try and figure
> >> > >> out what could be wrong.
> >> > >>
> >> > >> Also, you could try the 2.2.1 snapshots.   The code around the
> >> > >> wrapper
> >> > >> helpers
> >> > >> is very different in 2.2.1 so it MIGHT be fixed.   (I'm also fixing
> >> > >> the
> >> > >> fault
> >> > >> wrapping right now so stack traces from tonights snapshots should
> >> > >> be more useful)
> >> > >>
> >> > >> Dan
> >> > >>
> >> > >> On Thu April 16 2009 1:07:39 pm Bruno Aranda wrote:
> >> > >> > Hi,
> >> > >> >
> >> > >> > I have a web service using Apache CXF 2.2 that works smoothly
> >> > >> > (using
> >> > >> > soapUI). I have created a client, using JaxWsClientProxy (same
> >> > >> > CXF
> >> > >>
> >> > >> version)
> >> > >>
> >> > >> > and when invoking a method that
> >> > >> > has an array of complex objects as a parameter I get the
> >> > >> > following exception. However, everything runs fine for other
> >> > >> > methods of the
> >> > >>
> >> > >> service,
> >> > >>
> >> > >> > where strings or integers are passed. I have the impression this
> >> > >> > may
> >> > >> > be related to some dependency and I get the exception both in JSF
> >> > >> > 5 and 6.
> >> > >> >
> >> > >> > Do you have an idea where could I look? Thanks!
> >> > >> >
> >> > >> > Bruno
> >> > >> >
> >> > >> > Apr 16, 2009 5:27:55 PM
> >> > >> > org.apache.cxf.phase.PhaseInterceptorChain doIntercept
> >> > >> > INFO: Interceptor has thrown exception, unwinding now
> >> > >> > org.apache.cxf.interceptor.Fault
> >> > >> >     at
> >> > >>
> >> > >> org.apache.cxf.jaxws.interceptors.WrapperClassOutInterceptor.handle
> >> > >>Messa ge(
> >> > >>
> >> > >> >WrapperClassOutInterceptor.java:116) at
> >> > >>
> >> > >> org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterce
> >> > >>ptorC hai
> >> > >>
> >> > >> >n.java:236) at
> >> > >> > org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:469) at
> >> > >> > org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:299) at
> >> > >> > org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:251) at
> >> > >> > org.apache.cxf.frontend.ClientProxy.invokeSync(ClientProxy.java:7
> >> > >> >3) at
> >> > >> >
> >> > >> > org.apache.cxf.jaxws.JaxWsClientProxy.invoke(JaxWsClientProxy.jav
> >> > >> >a:124 ) at $Proxy62.getByInteractorList(Unknown Source)
> >> > >> >     at
> >> > >>
> >> > >> uk.ac.ebi.intact.psicquic.wsclient.MitabPsicquicClient.getByInterac
> >> > >>torLi st(
> >> > >>
> >> > >> >MitabPsicquicClient.java:104) at
> >> > >>
> >> > >> uk.ac.ebi.intact.psicquic.wsclient.MitabPsicquicClientTest.client(M
> >> > >>itabP sic
> >> > >>
> >> > >> >quicClientTest.java:37) at
> >> > >> > sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at
> >> > >>
> >> > >> sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImp
> >> > >>l.jav a:3
> >> > >>
> >> > >> >9) at
> >> > >>
> >> > >> sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAcc
> >> > >>essor Imp
> >> > >>
> >> > >> >l.java:25) at java.lang.reflect.Method.invoke(Method.java:585)
> >> > >> >     at
> >> > >>
> >> > >> org.junit.internal.runners.TestMethodRunner.executeMethodBody(TestM
> >> > >>ethod Run
> >> > >>
> >> > >> >ner.java:99) at
> >> > >>
> >> > >> org.junit.internal.runners.TestMethodRunner.runUnprotected(TestMeth
> >> > >>odRun ner
> >> > >>
> >> > >> >.java:81) at
> >> > >>
> >> > >> org.junit.internal.runners.BeforeAndAfterRunner.runProtected(Before
> >> > >>AndAf ter
> >> > >>
> >> > >> >Runner.java:34) at
> >> > >>
> >> > >> org.junit.internal.runners.TestMethodRunner.runMethod(TestMethodRun
> >> > >>ner.j ava
> >> > >>
> >> > >> >:75) at
> >> > >>
> >> > >> org.junit.internal.runners.TestMethodRunner.run(TestMethodRunner.ja
> >> > >>va:45 )
> >> > >>
> >> > >> >     at
> >> > >>
> >> > >> org.junit.internal.runners.TestClassMethodsRunner.invokeTestMethod(
> >> > >>TestC las
> >> > >>
> >> > >> >sMethodsRunner.java:75) at
> >> > >>
> >> > >> org.junit.internal.runners.TestClassMethodsRunner.run(TestClassMeth
> >> > >>odsRu nne
> >> > >>
> >> > >> >r.java:36) at
> >> > >>
> >> > >> org.junit.internal.runners.TestClassRunner$1.runUnprotected(TestCla
> >> > >>ssRun ner
> >> > >>
> >> > >> >.java:42) at
> >> > >>
> >> > >> org.junit.internal.runners.BeforeAndAfterRunner.runProtected(Before
> >> > >>AndAf ter
> >> > >>
> >> > >> >Runner.java:34) at
> >> > >> >
> >> > >> > org.junit.internal.runners.TestClassRunner.run(TestClassRunner.ja
> >> > >> >va:52 ) at
> >> > >>
> >> > >> com.intellij.rt.junit4.Junit4TestMethodAdapter.run(Junit4TestMethod
> >> > >>Adapt er.
> >> > >>
> >> > >> >java:62) at junit.textui.TestRunner.doRun(TestRunner.java:116)
> >> > >> >     at
> >> > >>
> >> > >> com.intellij.rt.execution.junit.IdeaTestRunner.doRun(IdeaTestRunner
> >> > >>.java
> >> > >>
> >> > >>:94
> >> > >>:
> >> > >> >) at junit.textui.TestRunner.doRun(TestRunner.java:109)
> >> > >> >     at
> >> > >>
> >> > >> com.intellij.rt.execution.junit.IdeaTestRunner.startRunnerWithArgs(
> >> > >>IdeaT est
> >> > >>
> >> > >> >Runner.java:22) at
> >> > >>
> >> > >> com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart
> >> > >>(JUni tSt
> >> > >>
> >> > >> >arter.java:118) at
> >> > >> >
> >> > >> > com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.ja
> >> > >> >va:40 ) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native
> >> > >> > Method) at
> >> > >>
> >> > >> sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImp
> >> > >>l.jav a:3
> >> > >>
> >> > >> >9) at
> >> > >>
> >> > >> sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAcc
> >> > >>essor Imp
> >> > >>
> >> > >> >l.java:25) at java.lang.reflect.Method.invoke(Method.java:585)
> >> > >> >     at
> >> > >>
> >> > >> com.intellij.rt.execution.application.AppMain.main(AppMain.java:90)
> >> > >>
> >> > >> > Caused by: org.apache.cxf.interceptor.Fault
> >> > >> >     at
> >> > >>
> >> > >> org.apache.cxf.jaxws.interceptors.WrapperHelper$ReflectWrapperHelpe
> >> > >>r.cre ate
> >> > >>
> >> > >> >WrapperObject(WrapperHelper.java:363) at
> >> > >>
> >> > >> org.apache.cxf.jaxws.interceptors.WrapperClassOutInterceptor.handle
> >> > >>Messa ge(
> >> > >>
> >> > >> >WrapperClassOutInterceptor.java:102) ... 35 more
> >> > >>
> >> > >> --
> >> > >> Daniel Kulp
> >> > >> dkulp@apache.org
> >> > >> http://www.dankulp.com/blog
> >>
> >> --
> >> Daniel Kulp
> >> dkulp@apache.org
> >> http://www.dankulp.com/blog

-- 
Daniel Kulp
dkulp@apache.org
http://www.dankulp.com/blog