Wicket
  1. Wicket
  2. WICKET-5256

Allow configuring the resource used by ResourceStreamRequestHandler

    Details

      Description

      During the migration from Wicket 1.4 to 1.5.10 I found out that the ResourceStreamResource.respond() does not set the ContentType charset if the resource is of type StringResourceStream. Even though the stream holds the charset, it is not set, although quite a few other header parameters are (well this is understandable because not all ResourceStreams are StringResourceStreams. Also, it is difficult to call the resource.setTextEncoding, because the current flow in resourceStreamRequestHandler.respond does not allow easy overriding of any smaller piece of respond than the whole method. The practical issue was to download a CSV file by clicking a button. I managed to fix the issue by copy/paste/Overriding the ResourceStreamRequestHandler.respond, but IMHO this is not nice:

      private void addCsvButton() {
      Form<?> form = new Form<Void>("form") {
      @Override
      protected void onSubmit() {
      final String fileName = getFileName("csv");
      TableCsvResourceFactory factory = new TableCsvResourceFactory();
      final IResourceStream resourceStream = factory.getResourceStream(tableModel.getObject());
      ResourceStreamRequestHandler resourceStreamRequestHandler = new ResourceStreamRequestHandler(
      resourceStream) {
      final ContentDisposition contentDisposition = ContentDisposition.ATTACHMENT;

      @Override
      public void respond(IRequestCycle requestCycle) {
      Attributes attributes = new Attributes(requestCycle.getRequest(), requestCycle.getResponse());

      ResourceStreamResource resource = new ResourceStreamResource(resourceStream);
      resource.setFileName(fileName);
      if (contentDisposition != null)

      { resource.setContentDisposition(contentDisposition); }

      else

      { resource.setContentDisposition(Strings.isEmpty(fileName) ? ContentDisposition.INLINE : ContentDisposition.ATTACHMENT); }

      final Duration cacheDuration = getCacheDuration();
      if (cacheDuration != null)

      { resource.setCacheDuration(cacheDuration); }

      + resource.setTextEncoding("UTF-8");

      resource.respond(attributes);
      }
      };
      RequestCycle.get().scheduleRequestHandlerAfterCurrent(resourceStreamRequestHandler);
      }
      };
      form.setVisible(displayCsv);
      add(form);
      }

      There are a couple of problems with the current implementation of ResourceStreamRequestHandler:
      1) I didn't figure out yet any other way how to call the
      resource.setTextEncoding("UTF-8");
      except by copy/pasting the whole ResourceStreamRequestHandler.respond() code to the Override. It would be nice, if there would be some cleaner hook to override some smaller part of this method, such as an empty default implementation of setTextEncoding() that would be always called but would not do anything for other types.

      2) A second approach would be to create a StringResourceStreamRequestHandler extends ResourceStreamRequestHandler that would be otherwise the same, but would use IStringResource instead of IResource, and would also set the TextEncoding.

      3) However, third, I didn't yet find any good way to get the encoding from the StringResourceStream itself, because the AbstractStringResourceStream has a protected getCharset(). This problem could be overcome by adding public version of getCharset() to StringResourceStream, or as I did, create a parallel subclass CharsetStringResourceStream that is a copy/paste from StringResourceStream but is non-final and has public getCharset(). After this you could dynamically set the text encoding in ResourceStreamRequestHandler.respond for example like this:

      if (getResourceStream() instanceof CharsetStringResourceStream)

      { resource.setTextEncoding(((CharsetStringResourceStream)getResourceStream()).getCharsetName()); }

      Anyway, I think the usage of StringResourceStream with ResourceStreamRequestHandler should be improved somehow, at the moment I think it is a bit awkward to use.

      1. WICKET-5256.patch
        2 kB
        Martin Grigorov

        Activity

        Hide
        Antti Hätinen added a comment -

        One addition: the practical issue is that in the HTTP header content-type you get only for example

        text/x-csv

        and I would like to get
        text/x-csv; charset=UTF-8

        Show
        Antti Hätinen added a comment - One addition: the practical issue is that in the HTTP header content-type you get only for example text/x-csv and I would like to get text/x-csv; charset=UTF-8
        Hide
        Martin Grigorov added a comment -

        Here is a possible improvement.
        A new method #configure(ResourceStreamResource) is introduced.
        This way you can do something like:

        ResourceStreamRequestHandler rsrh = new ResourceStreamRequestHandler(...) {
        @Override
        protected void configure(ResourceStreamResource resource)

        { super.configure(resource); resource.setXyz(...); }

        }

        Is this better ?

        Show
        Martin Grigorov added a comment - Here is a possible improvement. A new method #configure(ResourceStreamResource) is introduced. This way you can do something like: ResourceStreamRequestHandler rsrh = new ResourceStreamRequestHandler(...) { @Override protected void configure(ResourceStreamResource resource) { super.configure(resource); resource.setXyz(...); } } Is this better ?
        Hide
        Antti Hätinen added a comment -

        Exposing public getCharsetName() in StringBufferResourceStream would also do.

        Show
        Antti Hätinen added a comment - Exposing public getCharsetName() in StringBufferResourceStream would also do.
        Hide
        Antti Hätinen added a comment -

        Martin: Yes, I think that would be one good solution!

        Show
        Antti Hätinen added a comment - Martin: Yes, I think that would be one good solution!
        Hide
        Martin Grigorov added a comment -

        The improvement is applied.

        Show
        Martin Grigorov added a comment - The improvement is applied.

          People

          • Assignee:
            Martin Grigorov
            Reporter:
            Antti Hätinen
          • Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved:

              Development