You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user@struts.apache.org by Christopher Schultz <ch...@comcast.net> on 2004/06/11 23:44:29 UTC

NPE in forwardURL

Hello all,
I am in the process of upgrading from velocity-tools 1.0 to 
velocity-tools 1.1 in my existing Struts 1.1-based application.

This app was working perfectly before the upgrade (just one JAR file) 
and now I get an NPE whenever I use the velocity-tools's 
LinkTool.setForward() method.

Here's the relevant part of the stack trace:

java.lang.NullPointerException
	at org.apache.struts.util.RequestUtils.forwardURL(RequestUtils.java:1535)
	at 
org.apache.velocity.tools.struts.StrutsUtils.getForwardURL(StrutsUtils.java:593)
	at 
org.apache.velocity.tools.struts.StrutsLinkTool.setForward(StrutsLinkTool.java:82)

Line 593 of StrutsUtils.java is:

	url.append(RequestUtils.forwardURL(request, fc));

I've added logging to the class and I generate this output just before 
the call to forwardURL is made:

2004-06-11 16:50:16,081 [TP-Processor3] DEBUG crap- 
request=org.apache.coyote.tomcat4.CoyoteRequestFacade@167e3a5, 
fc=ForwardConfig[name=home,path=/index.vm,redirect=false,contextRelative=false]

So, I'm passing non-null values to RequestUtils.forwardURL.

Line 1534 and 1535 of RequestUtils.java are:

	ModuleConfig moduleConfig = (ModuleConfig) 
request.getAttribute(Globals.MODULE_KEY);
	String forwardPattern = 
moduleConfig.getControllerConfig().getForwardPattern();

I've added logging to the class and I generate this output just before 
the call to getControllerConfig():

2004-06-11 17:18:34,609 [TP-Processor3] DEBUG crap- moduleConfig = null, 
controllerConfig=[doh]

Where [doh] indicates that moduleConfig is null and therefore I can't 
actually find out what moduleConfig.getControllerConfig() would be.

As I said, everything was working fine before the velocity-tools 
upgrade, but the issue seems to be either with Struts or will some 
configuration of Struts.

I have a very simple struts-config.xml file. I'll spare you the details, 
but suffice it to say that I have the following in my config file:

- 2 form-beans
- 1 global-exception handler
- maybe a dozen global-forwards
- maybe a dozen action-mappings

That's it. I don't have any data-sources, controllers, or plug-ins 
defined. I'm not attempting any voodoo (that I know of) or using any 
weird custom anything.

I found this issue mentioned as bug 27080 
(http://issues.apache.org/bugzilla/show_bug.cgi?id=27080), and it was 
RESOLVED INVALID, with the comment that, in order to use 
RequestUtils.findForward, you must first invoke a Struts action.

By running the request first through a Struts action (really an action 
mapping which is really a forward directly to the .vm page), I get the 
following debugging output:

2004-06-11 17:38:12,166 [TP-Processor3] DEBUG crap- moduleConfig = 
org.apache.struts.config.impl.ModuleConfigImpl@d5c0f9, 
controllerConfig=ControllerConfig[bufferSize=4096,contentType=text/html,inputForward=false,locale=true,maxFileSize=250M,memFileSize=256K,multipartClass=org.apache.struts.upload.CommonsMultipartRequestHandler,nocache=false,processorClass=org.apache.struts.action.RequestProcessor]

and the page loads correctly.

Now, the ModuleConfig displayed in the debugging output is the same one 
that is available in the application scope, so it seems to me that I 
should not have to direct my page access through a Struts action since 
the ModuleConfig is available through the application (rather than the 
request).

Am I totally off the mark, here?

I don't claim to understand the subtleties of how Struts works in more 
complex environments (like with multiple modules, etc.) but I would 
think that a reasonable course of action would be:

	ModuleConfig moduleConfig = 
(ModuleConfig)request.getAttribute(Globals.MODULE_KEY);

	if(null == moduleConfig)
		moduleConfig = (ModuleConfig)application.getAttribute(Globals.MODULE_KEY);

	String forwardPattern = 
moduleConfig.getControllerConfig().getForwardPattern();

Any comments?

(and thanks for reading this insufferably long email... I just hate it 
when people don't do research and also don't post enough information)

-chris

Re: NPE in forwardURL

Posted by Niall Pemberton <ni...@blueyonder.co.uk>.
Chris,

Its an interesting point you raise about using a <logic:forward> tag in a
jsp without going through an Action. Looking at the Struts 1.1 code it looks
like it would work - ForwardTag calls
RequestUtils.getModuleConfig(HttpServletRequest, ServletContext) which does
exactly what you were hoping would have happened (i.e. getting it from
application scope if its not in the request).

Thinking about it this makes sense - if you forward directly to a jsp its
url doesn't have to be in appropriate format in which the module could be
determined and therefore it wouldn't be reliable - so the only thing to do
is assume its the default one if its not in the request [so ignore my
previous suggestion of getting Velocity tools changed to call
RequestUtils.selectModule()].

I believe your solution should work OK - whether you can get Velocity's
Struts tools to be changed to do the same thing is another matter - I guess
you need to make the case to them that its a valid scenario.

Good luck.

Niall

----- Original Message ----- 
From: "Christopher Schultz" <ch...@comcast.net>
To: "Struts Users Mailing List" <us...@struts.apache.org>
Sent: Saturday, June 12, 2004 2:42 AM
Subject: Re: NPE in forwardURL

Niall,

(First, let me say that I'm very happy to see such a great response so
fast. I really appreciate the time you took to research my problem and
make suggestions. I expected to suffer several rounds of "go away and
complain to the velocity tools guys" before getting anything useful.
Thanks!)

> I have to say I don't use velocity and so I don't really understand how
your
> using Struts without an Action, but anyway here goes...

Well, what's really going on is that I'm using a utility that should be
able to grab a global-forward from the struts configuration. I figured
that getting that value would be independent of the request actually
being touched by the Struts controller at some point.

> When modules were introduced in Struts 1.1 ActionServlet was modified so
> that every time a request was processed it stores the ModuleConfig as a
> parameter in the request under the key Globals.MODULE_KEY [if you look at
> the ActionServlet.process() method it calles RequestUtils.selectModule()
> which does this].

I noticed this, and it became part of my hacked solution (which was
actually hacked into velocity-tools, not struts). Velocity tools does
not mention its (in-)compatibility with either Struts 1.0 or Struts
1.1., so I figured it would be compatible with both. That is, velocity
tools 1.0 seemed to work fine with struts 1.0 /and/ 1.1, so it follows
that an upgrade from that should also work with struts 1.1.

> I understand you saying (paraphrasing) "if the ModuleConfig is not in the
> request scope it should use the application scope" in your context, but in
a
> Struts 1.1 context then it should be there and Struts code relying on that
> seems reasonable to me. What seems strange to me is that you are using
> Velocity's Struts tools outside of Struts.

I guess I look at it from the other side of the fence (literally, I
guess): I want Struts to give me information about its configuration,
and it seems like it should give up that information whether or not I've
actually sent my request through the ActionServlet.

> However if thats a valid use case
> in the Velocity world then maybe a change to the Velocity tools to call
the
> RequestUtils.selectModule() method as the ActionServlet does would be the
> best approach.

Honestly, I'm not sure whether or not this counts as a "valid use case
in the velocity world". Since the velocity-tools site doesn't
specifically state that use of the Struts* tools /requires/ the
ActionServlet, though it shows a diagram which has ActionServlet
handling the request and then forwarding to the VelocityViewServlet (the
one that handles requests for velocity templates).

Here's a good question: If I were to use the <struts:forward> tag from
the Struts taglib, and hit that JSP directly without going through a
Struts action, should I expect the same behavior? If so, then I'm just
breaking the rules and should shut up :)

> Short term I guess without going through ActionServlet you have to get the
> default module config stored in the request under the appropriate key.

This is exactly my hacked solution. It's funny... the method that calls
RequestUtils.forwardURL actually obtains the ModuleConfig in the very
first line of the method:

ModuleConfig moduleConfig = RequestUtils.getModuleConfig(request, app);

My solution was to add this code immediately before the call to
RequestUtils.forwardURL:

if(null == request.getAttribute(Globals.MODULE_KEY))
 request.setAttribute(Globals.MODULE_KEY, moduleConfig);

This seems to emulate the requirements that the ActionServlet fulfills.
I'll look into what AcionServlet does to see if there are any other laws
I'm breaking. I want to make sure that I'm not just getting lucky, here,
and not risking some other instabilities.

Thanks again for the great reply!

-chris



---------------------------------------------------------------------
To unsubscribe, e-mail: user-unsubscribe@struts.apache.org
For additional commands, e-mail: user-help@struts.apache.org


Re: NPE in forwardURL

Posted by Christopher Schultz <ch...@comcast.net>.
Niall,

(First, let me say that I'm very happy to see such a great response so 
fast. I really appreciate the time you took to research my problem and 
make suggestions. I expected to suffer several rounds of "go away and 
complain to the velocity tools guys" before getting anything useful. 
Thanks!)

> I have to say I don't use velocity and so I don't really understand how your
> using Struts without an Action, but anyway here goes...

Well, what's really going on is that I'm using a utility that should be 
able to grab a global-forward from the struts configuration. I figured 
that getting that value would be independent of the request actually 
being touched by the Struts controller at some point.

> When modules were introduced in Struts 1.1 ActionServlet was modified so
> that every time a request was processed it stores the ModuleConfig as a
> parameter in the request under the key Globals.MODULE_KEY [if you look at
> the ActionServlet.process() method it calles RequestUtils.selectModule()
> which does this].

I noticed this, and it became part of my hacked solution (which was 
actually hacked into velocity-tools, not struts). Velocity tools does 
not mention its (in-)compatibility with either Struts 1.0 or Struts 
1.1., so I figured it would be compatible with both. That is, velocity 
tools 1.0 seemed to work fine with struts 1.0 /and/ 1.1, so it follows 
that an upgrade from that should also work with struts 1.1.

> I understand you saying (paraphrasing) "if the ModuleConfig is not in the
> request scope it should use the application scope" in your context, but in a
> Struts 1.1 context then it should be there and Struts code relying on that
> seems reasonable to me. What seems strange to me is that you are using
> Velocity's Struts tools outside of Struts.

I guess I look at it from the other side of the fence (literally, I 
guess): I want Struts to give me information about its configuration, 
and it seems like it should give up that information whether or not I've 
actually sent my request through the ActionServlet.

> However if thats a valid use case
> in the Velocity world then maybe a change to the Velocity tools to call the
> RequestUtils.selectModule() method as the ActionServlet does would be the
> best approach.

Honestly, I'm not sure whether or not this counts as a "valid use case 
in the velocity world". Since the velocity-tools site doesn't 
specifically state that use of the Struts* tools /requires/ the 
ActionServlet, though it shows a diagram which has ActionServlet 
handling the request and then forwarding to the VelocityViewServlet (the 
one that handles requests for velocity templates).

Here's a good question: If I were to use the <struts:forward> tag from 
the Struts taglib, and hit that JSP directly without going through a 
Struts action, should I expect the same behavior? If so, then I'm just 
breaking the rules and should shut up :)

> Short term I guess without going through ActionServlet you have to get the
> default module config stored in the request under the appropriate key.

This is exactly my hacked solution. It's funny... the method that calls 
RequestUtils.forwardURL actually obtains the ModuleConfig in the very 
first line of the method:

ModuleConfig moduleConfig = RequestUtils.getModuleConfig(request, app);

My solution was to add this code immediately before the call to 
RequestUtils.forwardURL:

if(null == request.getAttribute(Globals.MODULE_KEY))
	request.setAttribute(Globals.MODULE_KEY, moduleConfig);

This seems to emulate the requirements that the ActionServlet fulfills. 
I'll look into what AcionServlet does to see if there are any other laws 
I'm breaking. I want to make sure that I'm not just getting lucky, here, 
and not risking some other instabilities.

Thanks again for the great reply!

-chris

Re: NPE in forwardURL

Posted by Niall Pemberton <ni...@blueyonder.co.uk>.
I have to say I don't use velocity and so I don't really understand how your
using Struts without an Action, but anyway here goes...

When modules were introduced in Struts 1.1 ActionServlet was modified so
that every time a request was processed it stores the ModuleConfig as a
parameter in the request under the key Globals.MODULE_KEY [if you look at
the ActionServlet.process() method it calles RequestUtils.selectModule()
which does this].

So RequestUtils.getForwardURL() tries to retrieve the ModuleConfig from the
request under this key. When you don't go through an Action (or more
importantly ActionServlet) it can't find it.

I understand you saying (paraphrasing) "if the ModuleConfig is not in the
request scope it should use the application scope" in your context, but in a
Struts 1.1 context then it should be there and Struts code relying on that
seems reasonable to me. What seems strange to me is that you are using
Velocity's Struts tools outside of Struts. However if thats a valid use case
in the Velocity world then maybe a change to the Velocity tools to call the
RequestUtils.selectModule() method as the ActionServlet does would be the
best approach.

One further point

Short term I guess without going through ActionServlet you have to get the
default module config stored in the request under the appropriate key.

Having said all that, maybe this is a common Velocity issue and if you ask
the question on a velocity list there might already be a solution for your
situation.

Niall

P.S. A quick look at StrutsUtils in velocity and there is a selectModule()
method in there - maybe creating your own custom version of the
StrutsLinkTool which calls that method first is the right way to go.

----- Original Message ----- 
From: "Christopher Schultz" <ch...@comcast.net>
To: <us...@struts.apache.org>
Cc: "Christopher Schultz" <ch...@comcast.net>
Sent: Friday, June 11, 2004 10:44 PM
Subject: NPE in forwardURL

Hello all,
I am in the process of upgrading from velocity-tools 1.0 to
velocity-tools 1.1 in my existing Struts 1.1-based application.

This app was working perfectly before the upgrade (just one JAR file)
and now I get an NPE whenever I use the velocity-tools's
LinkTool.setForward() method.

Here's the relevant part of the stack trace:

java.lang.NullPointerException
 at org.apache.struts.util.RequestUtils.forwardURL(RequestUtils.java:1535)
 at
org.apache.velocity.tools.struts.StrutsUtils.getForwardURL(StrutsUtils.java:
593)
 at
org.apache.velocity.tools.struts.StrutsLinkTool.setForward(StrutsLinkTool.ja
va:82)

Line 593 of StrutsUtils.java is:

 url.append(RequestUtils.forwardURL(request, fc));

I've added logging to the class and I generate this output just before
the call to forwardURL is made:

2004-06-11 16:50:16,081 [TP-Processor3] DEBUG crap-
request=org.apache.coyote.tomcat4.CoyoteRequestFacade@167e3a5,
fc=ForwardConfig[name=home,path=/index.vm,redirect=false,contextRelative=fal
se]

So, I'm passing non-null values to RequestUtils.forwardURL.

Line 1534 and 1535 of RequestUtils.java are:

 ModuleConfig moduleConfig = (ModuleConfig)
request.getAttribute(Globals.MODULE_KEY);
 String forwardPattern =
moduleConfig.getControllerConfig().getForwardPattern();

I've added logging to the class and I generate this output just before
the call to getControllerConfig():

2004-06-11 17:18:34,609 [TP-Processor3] DEBUG crap- moduleConfig = null,
controllerConfig=[doh]

Where [doh] indicates that moduleConfig is null and therefore I can't
actually find out what moduleConfig.getControllerConfig() would be.

As I said, everything was working fine before the velocity-tools
upgrade, but the issue seems to be either with Struts or will some
configuration of Struts.

I have a very simple struts-config.xml file. I'll spare you the details,
but suffice it to say that I have the following in my config file:

- 2 form-beans
- 1 global-exception handler
- maybe a dozen global-forwards
- maybe a dozen action-mappings

That's it. I don't have any data-sources, controllers, or plug-ins
defined. I'm not attempting any voodoo (that I know of) or using any
weird custom anything.

I found this issue mentioned as bug 27080
(http://issues.apache.org/bugzilla/show_bug.cgi?id=27080), and it was
RESOLVED INVALID, with the comment that, in order to use
RequestUtils.findForward, you must first invoke a Struts action.

By running the request first through a Struts action (really an action
mapping which is really a forward directly to the .vm page), I get the
following debugging output:

2004-06-11 17:38:12,166 [TP-Processor3] DEBUG crap- moduleConfig =
org.apache.struts.config.impl.ModuleConfigImpl@d5c0f9,
controllerConfig=ControllerConfig[bufferSize=4096,contentType=text/html,inpu
tForward=false,locale=true,maxFileSize=250M,memFileSize=256K,multipartClass=
org.apache.struts.upload.CommonsMultipartRequestHandler,nocache=false,proces
sorClass=org.apache.struts.action.RequestProcessor]

and the page loads correctly.

Now, the ModuleConfig displayed in the debugging output is the same one
that is available in the application scope, so it seems to me that I
should not have to direct my page access through a Struts action since
the ModuleConfig is available through the application (rather than the
request).

Am I totally off the mark, here?

I don't claim to understand the subtleties of how Struts works in more
complex environments (like with multiple modules, etc.) but I would
think that a reasonable course of action would be:

 ModuleConfig moduleConfig =
(ModuleConfig)request.getAttribute(Globals.MODULE_KEY);

 if(null == moduleConfig)
  moduleConfig = (ModuleConfig)application.getAttribute(Globals.MODULE_KEY);

 String forwardPattern =
moduleConfig.getControllerConfig().getForwardPattern();

Any comments?

(and thanks for reading this insufferably long email... I just hate it
when people don't do research and also don't post enough information)

-chris


---------------------------------------------------------------------
To unsubscribe, e-mail: user-unsubscribe@struts.apache.org
For additional commands, e-mail: user-help@struts.apache.org