You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user@struts.apache.org by Francisco José Aquino García <fj...@gmail.com> on 2009/06/25 19:52:36 UTC

[S2] Can't setBufferSize on StreamResult from action configuration (Struts2 2.1.6)

Hi,
  I've been coding an action which returns a streamed image based on
some image id. Quick and dirty, something like:

package org.chop.prjx.actions;

import java.io.*;
import java.slf4j.*;
import com.opensymphony.xwork2.ActionSupport;
import eu.medsea.mimeutil.MimeUtil;

public class ThumbnailAction extends ActionSupport {
  private static final Logger logger =
LoggerFactory.getLogger(ThumbnailAction.class);

  private String imageId;

  private BufferedInputStream imageStream;
  private String mimeType;
  private String fileName;
  private int bufSize = 1024;
  private String totSize="";


  public int getBuffSize() { return bufSize; }
  public void setBuffSize(int size) { bufSize = size; }

  public String getImageId() { return imageId; }
  public void setImageId(String id) { imageId = id; }


  public String execute() {
    logger.trace("(execute)");
    FileInputStream fis;
    String path = resolve(imageId);
    try {
      File f = new File(path);
      fileName = f.getName();
      totSize = Long.toString(f.length());
      mimeType =
MimeUtil.getMostSpecificMimeType(MimeUtil.getMimeTypes(f)).toString();
      fis = new FileInputStream(f);
      imageStream = new BufferedInputStream(fis, bufSize);
    } catch (FileNotFoundException e) {
      logger.error("(execute) Couldn't find: {}", path);
    }
    return SUCCESS;
  }

  public InputStream getInputStream() { return imageStream; }
  public String getMimeType() { return mimeType; }
  public String getFileName() { return fileName; }
  public String getLength() { return totSize; }

  public String resolve(final String id) {
    String retVal = "C:\\Java\\M\\Import\\" + id + ".mini.png";
    logger.debug("(resolve) id: {} --> path: {}", id, retVal);
    return retVal;
  }
}

My struts.xml file:
<struts>
  <constant name="struts.enable.DynamicMethodInvocation" value="false" />
  <constant name="struts.multipart.saveDir" value="/tmp" />
  <constant name="struts.url.includeParams" value="none" />

  <package name="admin" extends="struts-default">

    <interceptors>
      <interceptor-stack name="minimal">
        <interceptor-ref name="staticParams">
          <param name="parse">true</param>
        </interceptor-ref>
        <interceptor-ref name="params"/>
      </interceptor-stack>
    </interceptors>

    <action name="Image" class="org.chop.prjx.actions.ThumbnailAction">
      <interceptor-ref name="minima"/>

      <param name="buffSize">4096</param>

      <result type="stream">
        <param name="contentType">${mimeType}</param>
        <param name="contentLength">${length}</param>
        <param name="contentDisposition">inline; filename="${fileName}"</param>
        <param name="inputName">inputStream</param>
        <param name="bufferSize">${buffSize}</param>
        <param name="allowCaching">false</param>
      </result>
    </action>

    <action name="*">
      <result>/{1}.jsp</result>
    </action>

  </package>

</struts>

My idea was to be able to adjust the buffer size depending on
filesystem block size, average thumbnail size or whatever. However,
when invoking the action something bad happens:

GRAVE: Unable to set parameter [bufferSize] in result of type
[org.apache.struts2.dispatcher.StreamResult]
Caught OgnlException while setting property 'bufferSize' on type
'org.apache.struts2.dispatcher.StreamResult'. - Class:
ognl.OgnlRuntime
File: OgnlRuntime.java
Method: callAppropriateMethod
Line: 810 - ognl/OgnlRuntime.java:810:-1
    at com.opensymphony.xwork2.ognl.OgnlUtil.internalSetProperty(OgnlUtil.java:392)
    at com.opensymphony.xwork2.ognl.OgnlUtil.setProperty(OgnlUtil.java:143)
    at com.opensymphony.xwork2.ognl.OgnlReflectionProvider.setProperty(OgnlReflectionProvider.java:91)
    at com.opensymphony.xwork2.ObjectFactory.buildResult(ObjectFactory.java:221)
    at com.opensymphony.xwork2.DefaultActionInvocation.createResult(DefaultActionInvocation.java:208)
    ...
Caused by: java.lang.NoSuchMethodException: setBufferSize(java.lang.String)
    at ognl.OgnlRuntime.callAppropriateMethod(OgnlRuntime.java:810)
    at ognl.OgnlRuntime.setMethodValue(OgnlRuntime.java:964)
    at ognl.ObjectPropertyAccessor.setPossibleProperty(ObjectPropertyAccessor.java:75)
    at ognl.ObjectPropertyAccessor.setProperty(ObjectPropertyAccessor.java:131)
    at com.opensymphony.xwork2.ognl.accessor.ObjectAccessor.setProperty(ObjectAccessor.java:28)
    ... MUCH more

I've been peeking a little into
org.apache.struts2.dispatcher.StreamResult, and it indeed has a
property bufferSize of type int, but looks like OGNL keeps on
hammering a non-existent String one.
By the way, I also can't get the point of contentLengh being String.
In struts.xml, if instead of:
        <param name="bufferSize">${buffSize}</param>
I put:
        <param name="bufferSize">4096</param>
Then everything's ok, but it's something that's itching me. That, and
the fact that ThumbnailAction.setBuffSize() is invoked twice.

Well, I think that's all. Please excuse this long post. Any ideas?

Regards

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


Re: [S2] Can't setBufferSize on StreamResult from action configuration (Struts2 2.1.6)

Posted by Dale Newfield <da...@newfield.org>.
Francisco José Aquino García wrote:
> 2009/7/1 Dale Newfield <da...@newfield.org>:
>> May I ask why you need to dynamically change the buffer size?
> 
> to use the filesystem block size where the thumbnail resides as the
> bufferSize, as different thumbnails may reside in different
> filesystems

That sounds like a reasonable motivation.  Unfortunately as we've 
previously discussed, the current stream result object won't support 
dynamic values for this.  An evil workaround could be to configure a 
bunch of nearly identical results "success-stream-512", 
"success-stream-1024", "success-stream-8192", etc. and dispatch to the 
appropriate one.  A better solution would be to modify the stream 
result.  Patches are welcome to change that, and if you're quick (and if 
you smile sweetly at Musachy) you might be able to get that change into 
2.1.8...

> That's it. I didn't think very much about it really, I'm not an expert
> in Java IO so maybe this makes not much sense (the same goes for using
> BufferedInputStream instead of just the default InputStream.)

BufferedInputStream adds much more complexity and probably isn't 
necessary, but as long as it works...

-Dale

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


Re: [S2] Can't setBufferSize on StreamResult from action configuration (Struts2 2.1.6)

Posted by Francisco José Aquino García <fj...@gmail.com>.
2009/7/1 Dale Newfield <da...@newfield.org>:
> The problem is that there is no evaluation going on for that value.  If you
> need to dynamically set the buffer size, you'll need to use a different
> result implementation that accepts a string and evaluates it.  Extending
> StreamResult would get you most of the way there.  If you'd like to
> contribute your improvements back to the community, you can add those
> patches to a JIRA request.  May I ask why you need to dynamically change the
> buffer size?

ThumbnailAction uses a resolve() method that translates a document id
into a thumbnail filename to get the stream to the client. When I saw
that StreamResult uses a bufferSize parameter I thought that perhaps
it would be a good idea to use the filesystem block size where the
thumbnail resides as the bufferSize, as different thumbnails may
reside in different filesystems (it's hardcoded into the action in the
first post, but that path/filename will come out of a DB.) It will be
a very frequently used action, with anywhere between 2-200 thumbnails
per page.

That's it. I didn't think very much about it really, I'm not an expert
in Java IO so maybe this makes not much sense (the same goes for using
BufferedInputStream instead of just the default InputStream.)

-Fran Aquino

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


RE: [S2] Can't setBufferSize on StreamResult from action configuration (Struts2 2.1.6)

Posted by Martin Gainty <mg...@hotmail.com>.
you can override the bufferSize as seen in the result bufferSize param here

        <action name="download2" class="org.apache.struts2.showcase.filedownload.FileDownloadAction">
            <param name="inputPath">/images/struts-gif.zip</param>
            <result name="success" type="stream">
                <param name="contentType">application/zip</param>
                <param name="inputName">inputStream</param>
                <param name="contentDisposition">filename="struts-gif.zip"</param>
                <param name="bufferSize">4096</param>
            </result>
        </action>

org.apache.struts2.dispatcher.StreamResult contains resolveParamsFromStack
    protected void resolveParamsFromStack(ValueStack stack) {
.......
        Integer bufferSize = (Integer) stack.findValue("bufferSize", Integer.class);
        if (bufferSize != null) {
            setBufferSize(bufferSize.intValue());
        }
......
    }

bufferSize cannot exceed max int size
as mentioned the default buffersize of 1024 is usually more than adequate 

if you make the change to bufferSize attribute,accessor and mutator methods
we would like to see the refactor

thx
Martin 
______________________________________________ 
Verzicht und Vertraulichkeitanmerkung/Note de déni et de confidentialité
 
Diese Nachricht ist vertraulich. Sollten Sie nicht der vorgesehene Empfaenger sein, so bitten wir hoeflich um eine Mitteilung. Jede unbefugte Weiterleitung oder Fertigung einer Kopie ist unzulaessig. Diese Nachricht dient lediglich dem Austausch von Informationen und entfaltet keine rechtliche Bindungswirkung. Aufgrund der leichten Manipulierbarkeit von E-Mails koennen wir keine Haftung fuer den Inhalt uebernehmen.
Ce message est confidentiel et peut être privilégié. Si vous n'êtes pas le destinataire prévu, nous te demandons avec bonté que pour satisfaire informez l'expéditeur. N'importe quelle diffusion non autorisée ou la copie de ceci est interdite. Ce message sert à l'information seulement et n'aura pas n'importe quel effet légalement obligatoire. Étant donné que les email peuvent facilement être sujets à la manipulation, nous ne pouvons accepter aucune responsabilité pour le contenu fourni.




> Date: Tue, 30 Jun 2009 19:07:17 -0400
> From: dale@newfield.org
> To: user@struts.apache.org
> Subject: Re: [S2] Can't setBufferSize on StreamResult from action configuration (Struts2 2.1.6)
> 
> Francisco José Aquino García wrote:
> > 2009/6/26 Dale Newfield <da...@newfield.org>:
> >> The result doesn't evaluate bufferSize.  You can't put in OGNL there.
> > 
> > So... bufferSize in StreamResult would need to be parsed in a similar
> > way to contentLength to parse OGNL expressions?
> 
> Right.  There's no magic.  OGNL isn't magically replacing the expression 
> with a primitive that can be set as a primitive -- rather the result 
> accepts a string expression, assumes it's an ognl expression and 
> evaluates it, and uses the result of that evaluation as the value.
> 
> >> "${buffSize}" is a String.
> > 
> > Ok, I understand that as it isn't being parsed as OGNL bufferSize
> > won't accept anything but a literal, but why my expression is a
> > String, as buffSize is defined as int in ThumbnailAction? Surely my
> > understanding of OGNL is quite limited. How should I rewrite it to
> > evaluate as an int?
> 
> The problem is that there is no evaluation going on for that value.  If 
> you need to dynamically set the buffer size, you'll need to use a 
> different result implementation that accepts a string and evaluates it. 
>   Extending StreamResult would get you most of the way there.  If you'd 
> like to contribute your improvements back to the community, you can add 
> those patches to a JIRA request.  May I ask why you need to dynamically 
> change the buffer size?
> 
> -Dale
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: user-unsubscribe@struts.apache.org
> For additional commands, e-mail: user-help@struts.apache.org
> 

_________________________________________________________________
Hotmail® has ever-growing storage! Don’t worry about storage limits. 
http://windowslive.com/Tutorial/Hotmail/Storage?ocid=TXT_TAGLM_WL_HM_Tutorial_Storage_062009

Re: [S2] Can't setBufferSize on StreamResult from action configuration (Struts2 2.1.6)

Posted by Dale Newfield <da...@newfield.org>.
Francisco José Aquino García wrote:
> 2009/6/26 Dale Newfield <da...@newfield.org>:
>> The result doesn't evaluate bufferSize.  You can't put in OGNL there.
> 
> So... bufferSize in StreamResult would need to be parsed in a similar
> way to contentLength to parse OGNL expressions?

Right.  There's no magic.  OGNL isn't magically replacing the expression 
with a primitive that can be set as a primitive -- rather the result 
accepts a string expression, assumes it's an ognl expression and 
evaluates it, and uses the result of that evaluation as the value.

>> "${buffSize}" is a String.
> 
> Ok, I understand that as it isn't being parsed as OGNL bufferSize
> won't accept anything but a literal, but why my expression is a
> String, as buffSize is defined as int in ThumbnailAction? Surely my
> understanding of OGNL is quite limited. How should I rewrite it to
> evaluate as an int?

The problem is that there is no evaluation going on for that value.  If 
you need to dynamically set the buffer size, you'll need to use a 
different result implementation that accepts a string and evaluates it. 
  Extending StreamResult would get you most of the way there.  If you'd 
like to contribute your improvements back to the community, you can add 
those patches to a JIRA request.  May I ask why you need to dynamically 
change the buffer size?

-Dale

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


Re: [S2] Can't setBufferSize on StreamResult from action configuration (Struts2 2.1.6)

Posted by Francisco José Aquino García <fj...@gmail.com>.
2009/6/26 Dale Newfield <da...@newfield.org>:
> The result doesn't evaluate bufferSize.  You can't put in OGNL there.

So... bufferSize in StreamResult would need to be parsed in a similar
way to contentLength to parse OGNL expressions?


> "${buffSize}" is a String.

Ok, I understand that as it isn't being parsed as OGNL bufferSize
won't accept anything but a literal, but why my expression is a
String, as buffSize is defined as int in ThumbnailAction? Surely my
understanding of OGNL is quite limited. How should I rewrite it to
evaluate as an int?

Thanks for your attention.

-Fran Aquino

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


Re: [S2] Can't setBufferSize on StreamResult from action configuration (Struts2 2.1.6)

Posted by Dale Newfield <da...@newfield.org>.
Francisco José Aquino García wrote:
>       <result type="stream">
>         <param name="contentType">${mimeType}</param>
>         <param name="contentLength">${length}</param>
>         <param name="contentDisposition">inline; filename="${fileName}"</param>
>         <param name="inputName">inputStream</param>
>         <param name="bufferSize">${buffSize}</param>
>         <param name="allowCaching">false</param>
>       </result>
>     </action>

The result doesn't evaluate bufferSize.  You can't put in OGNL there.

> I've been peeking a little into
> org.apache.struts2.dispatcher.StreamResult, and it indeed has a
> property bufferSize of type int, but looks like OGNL keeps on
> hammering a non-existent String one.

"${buffSize}" is a String.

> By the way, I also can't get the point of contentLengh being String.

Did you notice where that string is explicitly parsed to extract a real 
value?

   198               // Set the content length
   199               if (contentLength != null) {
   200                   String _contentLength = 
conditionalParse(contentLength, invocation);
   201                   int _contentLengthAsInt = -1;
   202                   try {
   203                       _contentLengthAsInt = 
Integer.parseInt(_contentLength);
   204                       if (_contentLengthAsInt >= 0) {
   205 
oResponse.setContentLength(_contentLengthAsInt);
   206                       }
   207                   }
   208                   catch(NumberFormatException e) {
   209                       log.warn("failed to recongnize 
"+_contentLength+" as a number, contentLength header will not be set", e);
   210                   }
   211               }

-Dale


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