You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user@struts.apache.org by Robert Harrison <rh...@gmail.com> on 2006/11/08 18:14:05 UTC

Cannot Retrieve Request Parameter

I am trying to post a payment to a vendor and receive a response from the
vendor that the payment has been received.

Servlet "CreditCardPaymentAction" posts the payment information to the
vendor and returns null.
The postback url is "http://xxx/CreateUser.do" which maps to the
"CreateUserAction" servlet. In other words, I'm trying to post the
information to the vendor using  CreditCardPaymentAction and receive the
confirmation using CreateUserAction. The first part seems to work but, what
I get back is puzzling.

In  CreateUserAction getQueryString returns null. getParameter("xid")
returns null.
However, BufferedReader returns a jsp which contains the parameter("xid")
and its value indicating a successful transaction. The  problem is I can't
seem to retrieve it in the servlet.

I've Googled until I'm red in the face. Could someone tell me why I can't
retrieve the value for xid using getParameter("xid")? I've attached code
snippets below:

Struts-config.xml
<action path="/makePayment" input="/creditCardPayment.jsp"
name="CreditCardForm" scope="request" type="
com.beeslender.struts.CreditCardPaymentAction">
... None of the forwards are used
</action>
<action path="/createUser"  type="com.beeslender.struts.CreateUserAction">
        <forward name="create.user.success" path="/myPageSetup.do"/>
        <forward name="create.user.failure" path="/makePaymentPage.do"/>
</action>

CreditCardPaymentAction
        // Get the card information
        CreditCardForm creditCardForm = (CreditCardForm) form;
        // Assemble the credit card info for transmission to vendor
        // Constants come from properties
        StringBuffer parms = makeParms(userVO, creditCardForm, props);

        URL url = new URL(props.getString("credit.card.vendor.url"));
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        openConnection(conn);
        sendRequest(conn, parms);
        return null;

private void openConnection(HttpURLConnection conn)
    {
        conn.setDoInput(true);
        conn.setDoOutput(true);
        conn.setUseCaches(false);
    }

private void sendRequest(HttpURLConnection conn, StringBuffer parms)
    {
        DataOutputStream writer;
        conn.setRequestMethod("POST");
        conn.setRequestProperty
("Content-Type","application/x-www-form-urlencoded");
        writer = new DataOutputStream(conn.getOutputStream());
        writer.writeBytes(parms.toString());
        writer.flush();
        writer.close();
    }

CreateUserAction
        String xid = request.getParameter("xid");
        String s = request.getQueryString();
        System.out.println("The Query String is >>>>>" + s);

        BufferedReader in = new BufferedReader(request.getReader());
        String decodedString;
            while ((decodedString = in.readLine()) != null) {
                System.out.println(decodedString);
            }
        in.close();



Much Appreciated,

Bob Harrison
-- 
"In theory there is no difference between theory and practice. In practice
there is."
Yogi Berra

Re: Cannot Retrieve Request Parameter

Posted by Robert Harrison <rh...@gmail.com>.
Chris,
Thanks for your generosity.  I'll give your suggestions a whirl.

Bob

On 11/9/06, Christopher Schultz <ch...@christopherschultz.net> wrote:
>
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
>
> Robert,
>
> Robert Harrison wrote:
> > Here is a truncated version of makeparms.
> >
> >        String separator = new String("&");
> >        StringBuffer parms = new StringBuffer();
> >        String desc = props.getString("credit.card.description");
> >        String cost = props.getString("credit.card.amount");
> >
> >        parms.append("vendor_id=" + vendor_id + separator);
> >        parms.append("ret_addr=" + ret_addr + separator);
> >        parms.append("first_name=" + firstName + separator);
> >        parms.append("ret_mode=post" + separator);
> >        parms.append("post_back_on_error=1" + separator);
> >        parms.append("lookup=xid"); // Last item
>
> Just a quick note on style, etc.: if you are going to use the + operator
> to concatenate Strings, why are you using a StringBuffer? Since you've
> already got the SB, go ahead and use it. Also, there's no need for
> 'separator' to create a 'new String' out of an existing string.
>
> It does not appear that you use the locals 'desc' and 'cost', although
> you might use them later, as you mentioned that this is a truncated
> version of the method.
>
> Several things stick out as potential sticking points in this code, as
> well as the cost you posted before (that uses this code):
>
> 1. You are not encoding any of your data. You should be using
>    URLEncoder.encode(string, charset) on all unknown data to
>    protect against things like spaces and other illegal
>    url-encoded characters (particularly the ret_addr).
>
> 2. You are not using a well-known Content-Type when sending your
>    request. You should either explicitly use something like UTF-8
>    or ISO-8859-1 (the default).
>
> 3. You are not passing the Content-Length header to the server.
>    HTTP/1.1 does not mandate this field, but it's good form to include
>    it.
>
> May I suggest the following changes:
>
> // In your makeparms method:
>
> String charset = "UTF-8";
> char separator = '&';
> StringBuffer parms = new StringBuffer();
> parms.append("vendor_id=")
>      .append(URLEncode.encode(vendor_id, charset))
>      .append(separator);
>
> parms.append("ret_addr=")
>      .append(URLEncode.encode(ret_addr, charset))
>      .append(separator);
>   .
>   .
>   .
>
> // In your code that calls makeparm:
>
>       StringBuffer parms = makeParms(userVO, creditCardForm, props);
>       byte[] contentBytes = parms.toString().getBytes("UTF-8");
>
>       URL url = new URL(props.getString("credit.card.vendor.url"));
>       URLConnection c = url.openConnection();
>       if(!(c instanceof HttpURLConnection))
>            throw new RuntimeException("Expected HttpURLConnection, got "
>                                       + c.getClass());
>
>       HttpURLConnection conn = (HttpURLConnection)c;
>
>       conn.setDoOutput(true);  // Read-write
>       conn.setDoInput(true);   // Read-write
>       conn.setUseCaches(false);
>       conn.setRequestMethod("POST");
>       conn.setRequestProperty("Content-Type",
>              "application/x-www-form-urlencoded; charset=UTF-8");
>       conn.setRequestProperty("Content-length",
>              String.valueOf(contentBytes.length));
>       conn.setInstanceFollowRedirects(true); // Optional
>       conn.connect(); // Make the connection
>
>       OutputStream out = conn.getOutputStream();
>       out.write(contentBytes);
>       out.flush();
>       out.close();
>
>       // Do whatever you want with the response. Don't forget
>       // to appropriately detect the response's character encoding,
>       // HTTP status, etc. If there's a problem, read from the
>       // error stream, not from the "input stream". Otherwise, you'll
>       // get an exception.
>       InputStream in = conn.getInputStream();
>       // Whatever
>       in.close();
>
>
> I use this code in a component that I wrote to either GET or POST (this
> is the POST code) to a "fulfillment server" which creates records in a
> database for me.
>
> It works perfectly for me, although I haven't given you 100% of the code
> I've written (especially the part about reading the response).
>
> Hope this helps,
>
> - -chris
> -----BEGIN PGP SIGNATURE-----
> Version: GnuPG v1.4.5 (MingW32)
> Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org
>
> iD8DBQFFU0/09CaO5/Lv0PARAs5ZAJ0TCG+C8BftGIqRtS6FI5ArHPPoNgCfejsN
> z7rmVDvdwQrz/xTh18+F+to=
> =QQVm
> -----END PGP SIGNATURE-----
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: user-unsubscribe@struts.apache.org
> For additional commands, e-mail: user-help@struts.apache.org
>
>

Re: Cannot Retrieve Request Parameter

Posted by Christopher Schultz <ch...@christopherschultz.net>.
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Robert,

Robert Harrison wrote:
> Here is a truncated version of makeparms.
> 
>        String separator = new String("&");
>        StringBuffer parms = new StringBuffer();
>        String desc = props.getString("credit.card.description");
>        String cost = props.getString("credit.card.amount");
> 
>        parms.append("vendor_id=" + vendor_id + separator);
>        parms.append("ret_addr=" + ret_addr + separator);
>        parms.append("first_name=" + firstName + separator);
>        parms.append("ret_mode=post" + separator);
>        parms.append("post_back_on_error=1" + separator);
>        parms.append("lookup=xid"); // Last item

Just a quick note on style, etc.: if you are going to use the + operator
to concatenate Strings, why are you using a StringBuffer? Since you've
already got the SB, go ahead and use it. Also, there's no need for
'separator' to create a 'new String' out of an existing string.

It does not appear that you use the locals 'desc' and 'cost', although
you might use them later, as you mentioned that this is a truncated
version of the method.

Several things stick out as potential sticking points in this code, as
well as the cost you posted before (that uses this code):

1. You are not encoding any of your data. You should be using
   URLEncoder.encode(string, charset) on all unknown data to
   protect against things like spaces and other illegal
   url-encoded characters (particularly the ret_addr).

2. You are not using a well-known Content-Type when sending your
   request. You should either explicitly use something like UTF-8
   or ISO-8859-1 (the default).

3. You are not passing the Content-Length header to the server.
   HTTP/1.1 does not mandate this field, but it's good form to include
   it.

May I suggest the following changes:

// In your makeparms method:

String charset = "UTF-8";
char separator = '&';
StringBuffer parms = new StringBuffer();
parms.append("vendor_id=")
     .append(URLEncode.encode(vendor_id, charset))
     .append(separator);

parms.append("ret_addr=")
     .append(URLEncode.encode(ret_addr, charset))
     .append(separator);
  .
  .
  .

// In your code that calls makeparm:

      StringBuffer parms = makeParms(userVO, creditCardForm, props);
      byte[] contentBytes = parms.toString().getBytes("UTF-8");

      URL url = new URL(props.getString("credit.card.vendor.url"));
      URLConnection c = url.openConnection();
      if(!(c instanceof HttpURLConnection))
           throw new RuntimeException("Expected HttpURLConnection, got "
                                      + c.getClass());

      HttpURLConnection conn = (HttpURLConnection)c;

      conn.setDoOutput(true);  // Read-write
      conn.setDoInput(true);   // Read-write
      conn.setUseCaches(false);
      conn.setRequestMethod("POST");
      conn.setRequestProperty("Content-Type",
             "application/x-www-form-urlencoded; charset=UTF-8");
      conn.setRequestProperty("Content-length",
             String.valueOf(contentBytes.length));
      conn.setInstanceFollowRedirects(true); // Optional
      conn.connect(); // Make the connection

      OutputStream out = conn.getOutputStream();
      out.write(contentBytes);
      out.flush();
      out.close();

      // Do whatever you want with the response. Don't forget
      // to appropriately detect the response's character encoding,
      // HTTP status, etc. If there's a problem, read from the
      // error stream, not from the "input stream". Otherwise, you'll
      // get an exception.
      InputStream in = conn.getInputStream();
      // Whatever
      in.close();


I use this code in a component that I wrote to either GET or POST (this
is the POST code) to a "fulfillment server" which creates records in a
database for me.

It works perfectly for me, although I haven't given you 100% of the code
I've written (especially the part about reading the response).

Hope this helps,

- -chris
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.5 (MingW32)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iD8DBQFFU0/09CaO5/Lv0PARAs5ZAJ0TCG+C8BftGIqRtS6FI5ArHPPoNgCfejsN
z7rmVDvdwQrz/xTh18+F+to=
=QQVm
-----END PGP SIGNATURE-----

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


Re: Cannot Retrieve Request Parameter

Posted by Robert Harrison <rh...@gmail.com>.
Chris,
Thanks for your suggestions/questions.

Here is a truncated version of makeparms.

private StringBuffer makeParms(UserVO userVO,
CreditCardForm creditCardForm, ResourceBundle props) {
        // variables for cc vendor
        String separator = new String("&");
        StringBuffer parms = new StringBuffer();
        String desc = props.getString("credit.card.description");
        String cost = props.getString("credit.card.amount");

        parms.append("vendor_id=" + vendor_id + separator);
        parms.append("ret_addr=" + ret_addr + separator);
        parms.append("first_name=" + firstName + separator);
        parms.append("ret_mode=post" + separator);
        parms.append("post_back_on_error=1" + separator);
        parms.append("lookup=xid"); // Last item

        return (parms);


Bob

On 11/8/06, Christopher Schultz <ch...@christopherschultz.net> wrote:
>
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
>
> Robert,
>
> Robert Harrison wrote:
> > CreditCardPaymentAction
> >        StringBuffer parms = makeParms(userVO, creditCardForm, props);
> >        sendRequest(conn, parms);
>
> > private void sendRequest(HttpURLConnection conn, StringBuffer parms)
> >    {
> >        DataOutputStream writer;
> >        conn.setRequestMethod("POST");
> >        conn.setRequestProperty
> > ("Content-Type","application/x-www-form-urlencoded");
> >        writer = new DataOutputStream(conn.getOutputStream());
> >        writer.writeBytes(parms.toString());
> >        writer.flush();
> >        writer.close();
> >    }
>
> It would seem that you haven't provided the code to the "makeParms"
> method, which could be the source of your problem. Note that you ought
> to include ";charset=[your character set]" after your content type's
> mime type, just to be explicit about what you are sending to the remote
> host.
>
> > CreateUserAction
> >        String xid = request.getParameter("xid");
> >        String s = request.getQueryString();
> >        System.out.println("The Query String is >>>>>" + s);
> >
> >        BufferedReader in = new BufferedReader(request.getReader());
>
> Using request.getParameter and request.getReader (or
> request.getInputStream) rarely work well together, since
> request.getParameter requires parsing the input stream to get POST
> parameters. My guess is that you are not sending a correct POST body,
> and you parameters aren't being read by request.getParameter. But, that
> request body is still available for reading by this code:
>
> >        String decodedString;
> >            while ((decodedString = in.readLine()) != null) {
> >                System.out.println(decodedString);
> >            }
>
> So, what does your POST request look like, then?
>
> - -chris
>
> -----BEGIN PGP SIGNATURE-----
> Version: GnuPG v1.4.5 (MingW32)
> Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org
>
> iD8DBQFFUk9E9CaO5/Lv0PARAi/uAJ4jlNPZTqMtStVKoijquNg2qXGikQCgsuwy
> lQfLBTPq8v0B9pFRp8FLHfk=
> =tcQB
> -----END PGP SIGNATURE-----
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: user-unsubscribe@struts.apache.org
> For additional commands, e-mail: user-help@struts.apache.org
>
>

Re: [OT] Deploy Images externally from application

Posted by Christopher Schultz <ch...@christopherschultz.net>.
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Affan,

AQureshi@epsilon.com wrote:
> I have an application which contains a bunch of images for products whose 
> filenames come from the database. Right now the images are stored inside 
> the WAR file when deploying the application

Ugh.

> We don't care about versioning image files since they are maintained
> by a third party.

Yeah, get those things out of CVS.

> I wish to know what approach would be the best to keep the images outside 
> of the built WAR and still being able to access them easily from the 
> application. Some approached I thought of were: 
> 
> - Maintain images in a separate CVS module. When deploying the application 
> explode the WAR file and include the images and re-war the war file. 

Why bother with CVS? Why bother with a WAR? Why bother with deployment?
Just keep them in the same place all the time.

> - Store images in a separate folder outside of the context root and refer 
> to them via a symlink (platform dependent) or a configuration property in 
> the application (platform independent). 

The symlink is not necessary.

I think you should just allocate a portion of your URL-space to these
images. Something like "/images", maybe.

You ought to be able to divert a particular URL space to another
directory which is external to your webapp (i.e. not stored in the
"myapp" directory under your servlet container's deployment directory).
For instance, in Apache httpd, you could do this:

Alias /images /full/path/to/your/image/repository

I would imagine that Jakarta Tomcat has the same capability, though I
have no idea how to configure it.

If you do something like this, you can keep your images in a directory
structure that is completely independent of your webapp, and doesn't
have to be handled specially during deployment of new webapp versions
(or even additional webapps).

If you make the "URL prefix" for those images dynamic within your
application, you can do something like this:

  <a href="${image-prefix}/{$image-path}">View Image</a>

Your image-prefix could even be fully-qualified (i.e. starting with
http://) and you could use a different server altogether to serve those
images. In fact, if you have a third-party who maintains your images,
you might even be able to serve these images from /their/ servers.

Hope that helps,
- -chris
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.5 (MingW32)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iD8DBQFFU8d39CaO5/Lv0PARAobKAJ9Je01VRGJf4e4ctgVwraZdXF7ouACghuWA
DFJwCQB57GQWG8N9MjX0ILk=
=eceU
-----END PGP SIGNATURE-----

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


Re: Deploy Images externally from application

Posted by AQ...@epsilon.com.
Maybe a taglib would be a better solution? Anyone else had to do this?

AQureshi@epsilon.com wrote on 11/09/2006 10:31:49 AM:

> Hello,
> 
> I have an application which contains a bunch of images for products 
whose 
> filenames come from the database. Right now the images are stored inside 

> the WAR file when deploying the application, which is fine but the 
problem 
> is that when they become part of the CVS code repository it becomes a 
huge 
> tarball and unnecessary duplication/tagging/branching of images on CVS 
> which do not change between releases. (We don't care about versioning 
> image files since they are maintained by a third party).
> 
> I wish to know what approach would be the best to keep the images 
outside 
> of the built WAR and still being able to access them easily from the 
> application. Some approached I thought of were: 
> 
> - Maintain images in a separate CVS module. When deploying the 
application 
> explode the WAR file and include the images and re-war the war file. 
> - Store images in a separate folder outside of the context root and 
refer 
> to them via a symlink (platform dependent) or a configuration property 
in 
> the application (platform independent). 
> 
> Does anyone know of a better solution? Or has any comments/ideas on how 
to 
> do this?
> 
> Thanks a lot!
> 
> Affan
> 
> 
> 

[OT] Deploy Images externally from application

Posted by AQ...@epsilon.com.
Hello,

I have an application which contains a bunch of images for products whose 
filenames come from the database. Right now the images are stored inside 
the WAR file when deploying the application, which is fine but the problem 
is that when they become part of the CVS code repository it becomes a huge 
tarball and unnecessary duplication/tagging/branching of images on CVS 
which do not change between releases. (We don't care about versioning 
image files since they are maintained by a third party).

I wish to know what approach would be the best to keep the images outside 
of the built WAR and still being able to access them easily from the 
application. Some approached I thought of were: 

- Maintain images in a separate CVS module. When deploying the application 
explode the WAR file and include the images and re-war the war file. 
- Store images in a separate folder outside of the context root and refer 
to them via a symlink (platform dependent) or a configuration property in 
the application (platform independent). 

Does anyone know of a better solution? Or has any comments/ideas on how to 
do this?

Thanks a lot!

Affan




Re: Cannot Retrieve Request Parameter

Posted by Christopher Schultz <ch...@christopherschultz.net>.
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Robert,

Robert Harrison wrote:
> CreditCardPaymentAction
>        StringBuffer parms = makeParms(userVO, creditCardForm, props);
>        sendRequest(conn, parms);

> private void sendRequest(HttpURLConnection conn, StringBuffer parms)
>    {
>        DataOutputStream writer;
>        conn.setRequestMethod("POST");
>        conn.setRequestProperty
> ("Content-Type","application/x-www-form-urlencoded");
>        writer = new DataOutputStream(conn.getOutputStream());
>        writer.writeBytes(parms.toString());
>        writer.flush();
>        writer.close();
>    }

It would seem that you haven't provided the code to the "makeParms"
method, which could be the source of your problem. Note that you ought
to include ";charset=[your character set]" after your content type's
mime type, just to be explicit about what you are sending to the remote
host.

> CreateUserAction
>        String xid = request.getParameter("xid");
>        String s = request.getQueryString();
>        System.out.println("The Query String is >>>>>" + s);
> 
>        BufferedReader in = new BufferedReader(request.getReader());

Using request.getParameter and request.getReader (or
request.getInputStream) rarely work well together, since
request.getParameter requires parsing the input stream to get POST
parameters. My guess is that you are not sending a correct POST body,
and you parameters aren't being read by request.getParameter. But, that
request body is still available for reading by this code:

>        String decodedString;
>            while ((decodedString = in.readLine()) != null) {
>                System.out.println(decodedString);
>            }

So, what does your POST request look like, then?

- -chris

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.5 (MingW32)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iD8DBQFFUk9E9CaO5/Lv0PARAi/uAJ4jlNPZTqMtStVKoijquNg2qXGikQCgsuwy
lQfLBTPq8v0B9pFRp8FLHfk=
=tcQB
-----END PGP SIGNATURE-----

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