Saturday 8 May 2010

Spring error message - "can't parse argument number"

PROBLEM:
The story:
I want to display an error message that contains two dates which are derived from the exception returned by a remote web service that I'm calling from the webapp.

I'm almost there, since this error seems to relate to the display of the message, and the log also shows lines where it is going wrong in the JSP (the one with "form:errors")

2010-05-08 15:28:21,237 DEBUG
[org.springframework.context.support.ResourceBundleMessageSource] -
<Creating MessageFormat for pattern [New bulletin cannot be created
until conflicting bulletins from {} to {} are recalled.] and locale 'en'>
2010-05-08 15:28:21,362 ERROR
[org.springframework.web.servlet.tags.form.ErrorsTag] - <can't parse
argument number >
java.lang.IllegalArgumentException: can't parse argument number
       at java.text.MessageFormat.makeFormat(MessageFormat.java:1330)
       at java.text.MessageFormat.applyPattern(MessageFormat.java:450)
       at java.text.MessageFormat.<init>(MessageFormat.java:368)
       at org.springframework.context.support.MessageSourceSupport.createMessageFormat(MessageSourceSupport.java:118)
       at org.springframework.context.support.ResourceBundleMessageSource.getMessageFormat(ResourceBundleMessageSource.java:277)
       at org.springframework.context.support.ResourceBundleMessageSource.resolveCode(ResourceBundleMessageSource.java:184)
       at org.springframework.context.support.AbstractMessageSource.getMessageInternal(AbstractMessageSource.java:205)

SOLUTION:
The error is occurring because the error message I'm using from messages.properties is:
admin.bulletin.previousBulletin.notRecalled = New bulletin cannot be created until conflicting bulletins from {} to {} are recalled.

when it should be:
admin.bulletin.previousBulletin.notRecalled = New bulletin cannot be created until conflicting bulletins from {0} to {1} are recalled.

Error in webapp - javax/xml/soap/Detail violates loader constraints

added this to my pom.xml

<dependency>
<groupId>javax.xml.soap</groupId>
<artifactId>saaj-api</artifactId>
<version>1.3</version>
</dependency>

because i could not get the SOAPFaultException.Detail value

and got this when exception was being handled

2010-05-08 16:22:41,039 ERROR
[org.springframework.web.portlet.DispatcherPortlet] - <Could not
complete request>
javax.portlet.PortletException: Error occured during request
processing: Class javax/xml/soap/Detail violates loader constraints
at org.springframework.web.portlet.DispatcherPortlet.doActionService(DispatcherPortlet.java:715)
at org.springframework.web.portlet.FrameworkPortlet.processRequest(FrameworkPortlet.java:480)
at org.springframework.web.portlet.FrameworkPortlet.processAction(FrameworkPortlet.java:462)
at com.vignette.portal.portlet.jsrcontainer.internal.standardcontainer.management.FilterChainImpl.doFilter(FilterChainImpl.java:204)
at com.vignette.portal.portlet.jsrcontainer.internal.standardcontainer.management.FilterManagerImpl.processFilter(FilterManagerImpl.java:67)
at com.vignette.portal.portlet.jsrcontainer.internal.standardcontainer.invocation.ProcessActionCommand.execute(ProcessActionCommand.java:62)
at com.vignette.portal.portlet.jsrcontainer.PortletCommandServlet.service(PortletCommandServlet.java:170)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)


because I should have set dependency scope to "provided"

<dependency>
<groupId>javax.xml.soap</groupId>
<artifactId>saaj-api</artifactId>
<version>1.3</version>
<scope>provided</scope>
</dependency>

Friday 7 May 2010

Exotic error message of the week (Spring transactions) - "Application exception overridden by commit exception"

The @Transactional annotation in Spring makes it easy to make things
uh, transactional, right? So why did I get this stackTrace when I
threw an expected exception?

The web service I was testing returned this response:

<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
<env:Header/>
<env:Body>
<env:Fault xmlns:fault="http://schemas.xmlsoap.org/soap/envelope/">
<faultcode>fault:CO10001</faultcode>
<faultstring>An unknown error occurred</faultstring>
<faultactor>AdminService</faultactor>
<detail>
<java:string xmlns:java="java.io">Transaction rolled back
because it has been marked as rollback-only</java:string>
</detail>
</env:Fault>
</env:Body>
</env:Envelope>


And the log file contained this:


ERROR [Fri May 7 18:29:46 EST 2010:] [[ACTIVE] ExecuteThread: '0' for
queue: 'weblogic.kernel.Default (self-tuning)'] [string] [367]
org.springframework.transaction.interceptor.TransactionInterceptor :
Application exception overridden by commit exception
mycompany.exception.Exception: Bulletin cannot be created because
of active bulletins that were created between 28/04/2010 and
06/05/2010
at mycompany.domain.service.spring.SpringAdminDomainService.checkForExistingBulletins(SpringAdminDomainService.java:441)
at mycompany.domain.service.spring.SpringAdminDomainService.createBulletin(SpringAdminDomainService.java:384)
at mycompany.domain.service.spring.SpringAdminDomainService.manageBulletin(SpringAdminDomainService.java:87)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:307)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:182)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:149)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:106)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204)
at $Proxy391.manageBulletin(Unknown Source)
at mycompany.application.facade.spring.SpringAdminFacade.manageBulletin(SpringAdminFacade.java:183)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:307)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:182)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:149)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:106)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204)
at $Proxy392.manageBulletin(Unknown Source)
at mycompany.package.service.ws.jws.JwsAdminService.manageBulletin(JwsAdminService.java:120)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at weblogic.wsee.component.pojo.JavaClassComponent.invoke(JavaClassComponent.java:99)
at weblogic.wsee.ws.dispatch.server.ComponentHandler.handleRequest(ComponentHandler.java:64)
at weblogic.wsee.handler.HandlerIterator.handleRequest(HandlerIterator.java:137)
at weblogic.wsee.ws.dispatch.server.ServerDispatcher.dispatch(ServerDispatcher.java:109)
at weblogic.wsee.ws.WsSkel.invoke(WsSkel.java:80)
at weblogic.wsee.server.servlet.SoapProcessor.handlePost(SoapProcessor.java:66)
at weblogic.wsee.server.servlet.SoapProcessor.process(SoapProcessor.java:44)
at weblogic.wsee.server.servlet.BaseWSServlet$AuthorizedInvoke.run(BaseWSServlet.java:257)
at weblogic.wsee.server.servlet.BaseWSServlet.service(BaseWSServlet.java:156)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:820)
at weblogic.servlet.internal.StubSecurityHelper$ServletServiceAction.run(StubSecurityHelper.java:226)
at weblogic.servlet.internal.StubSecurityHelper.invokeServlet(StubSecurityHelper.java:124)
at weblogic.servlet.internal.ServletStubImpl.execute(ServletStubImpl.java:283)
at weblogic.servlet.internal.TailFilter.doFilter(TailFilter.java:26)
at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:42)
at com.jamonapi.JAMonFilter.doFilter(JAMonFilter.java:57)
at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:42)
at weblogic.servlet.internal.WebAppServletContext$ServletInvocationAction.run(WebAppServletContext.java:3393)
at weblogic.security.acl.internal.AuthenticatedSubject.doAs(AuthenticatedSubject.java:321)
at weblogic.security.service.SecurityManager.runAs(Unknown Source)
at weblogic.servlet.internal.WebAppServletContext.securedExecute(WebAppServletContext.java:2140)
at weblogic.servlet.internal.WebAppServletContext.execute(WebAppServletContext.java:2046)
at weblogic.servlet.internal.ServletRequestImpl.run(ServletRequestImpl.java:1366)
at weblogic.work.ExecuteThread.execute(ExecuteThread.java:200)
at weblogic.work.ExecuteThread.run(ExecuteThread.java:172)
DEBUG [Fri May 7 18:29:46 EST 2010:] [[ACTIVE] ExecuteThread: '0' for
queue: 'weblogic.kernel.Default (self-tuning)'] [string] [146]
mycompany.package.service.ws.jws.JwsAdminService : Raising
SOAPFaultException:
faultCode: {http://schemas.xmlsoap.org/soap/envelope/}CO10001
faultString: An unknown error occurred
faultActor: AdminService
exception: org.springframework.transaction.UnexpectedRollbackException:
Transaction rolled back because it has been marked as rollback-only
ERROR [Fri May 7 18:29:46 EST 2010:] [[ACTIVE] ExecuteThread: '0' for
queue: 'weblogic.kernel.Default (self-tuning)'] [string] [152]
mycompany.package.service.ws.jws.JwsAdminService : unexpected
exception
org.springframework.transaction.UnexpectedRollbackException:
Transaction rolled back because it has been marked as rollback-only
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:695)


Googling on "Application exception overridden by commit exception"
told us that it happens when an exception is thrown but the class is
not marked to rollback on that exception, so it continues and tries to
do a commit. Which isn't the case in my class since I had
rollbackOn=Throwable.class -- so rolling back on ALL exceptions,
including custom checked exceptions.


But then I looked into my classes and my hierarchy is like
Facade ---> Service class
Now what happens is that BOTH are annotated with @Transactional
I think if this is the cause, but I've removed the ones in the
lower-layer class (Service) and left it only in Facade class
(after testing)


That did the trick!!


The lesson for the day:


Multiple levels of @Transactional is not good. Set your transaction
boundaries in the uppermost layer where it's relevant, and that's it.


The service now returns:
<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
<env:Header/>
<env:Body>
<env:Fault xmlns:fault="http://schemas.xmlsoap.org/soap/envelope/">
<faultcode>fault:OPC10608</faultcode>
<faultstring>Bulletins exist that must be recalled</faultstring>
<faultactor>AdminService</faultactor>
<detail>
<java:string xmlns:java="java.io">Bulletin cannot be
created because of active bulletins that were created between
28/04/2010 and 06/05/2010</java:string>
</detail>
</env:Fault>
</env:Body>
</env:Envelope>


Which is what I want.


Hope this helps someone out there!