Sure, that'll work, too. However, a reason to prefer the Guava approach
over SequenceInputStream is to preserve incremental iterability without
having to implement tricky iteration logic:

InputSupplier<InputStream> joinedInputs = ByteStreams.join(
    FluentIterable.from(urls).transform(
        new Function<URL, InputSupplier<InputStream>>() {
            public InputSupplier<InputStream> apply(URL url) {
                return Resources.newInputStreamSupplier(url);
            }
        }
    )
);
InputRepresentation rep = new InputRepresentation(joinedInputs.get());


The transform and join calls are evaluated lazily. It would be much more
complicated to set up an Enumeration that manages opening and closing
InputStreams explicitly.

Note that FluentIterable is available as of Guava 12.0-rc1.

Side note: The InputSupplier and OutputSupplier abstractions in Guava would
be a great way to provide re-readable Restlet representations based on
InputStreams, OutputStreams, Readers, and Writers.

--tim

On Wed, Apr 18, 2012 at 12:48 PM, Thierry Boileau <
thierry.boil...@restlet.com> wrote:

> Hi Tim,
>
> thanks for the tips, I was a little bit lazy to look for convenient
> existing solutions... :)
> I've also discovered this class from the JDK1.6 :
> http://docs.oracle.com/javase/6/docs/api/java/io/SequenceInputStream.html
>
> Best regards,
> Thierry Boileau
>
>
> Guava has a method to join a sequence of input streams into one input
>> stream that might be useful here:
>>
>>
>> http://docs.guava-libraries.googlecode.com/git-history/v12.0/javadoc/com/google/common/io/ByteStreams.html#join(java.lang.Iterable)
>>
>> It actually works in terms of an Iterable (or array) of
>> InputSupplier<InputStream>. There is also a method to turn a URL into an
>> input stream supplier:
>>
>>
>> http://docs.guava-libraries.googlecode.com/git-history/v12.0/javadoc/com/google/common/io/Resources.html#newInputStreamSupplier(java.net.URL)
>>
>> --tim
>>
>>
>> On Wed, Apr 18, 2012 at 12:07 PM, Thierry Boileau <
>> thierry.boil...@restlet.com> wrote:
>>
>>> Hello Bjorn,
>>>
>>>
>>> >By messing with the code you sent, this seems to be a function of
>>> setting the representation size. If I set the size, it's fine, if not, it
>>> sends the whole thing regardless of content-range, which seems like a bug.
>>> Thanks for discovering a bug inside the RangeFilter class.
>>>
>>> Then, I've found that the problem is due to the usage of the
>>> OutputRepresentation in order to gather the several instances of
>>> InputStream. I propose you to use an InputRepresentation instead.
>>> First, I've set up a InputStream class that composes the several
>>> InputStream (this implementation is only a "quick" code):
>>>
>>>     private static class CompositeInputStream extends InputStream {
>>>         private Iterator<URL> urlIt = null;
>>>         private InputStream is = null;
>>>
>>>         public CompositeInputStream(Vector<URL> urls) throws IOException
>>> {
>>>             urlIt = urls.iterator();
>>>             if (urlIt.hasNext()) {
>>>                 is = urlIt.next().openStream();
>>>             }
>>>         }
>>>
>>>         @Override
>>>         public int read() throws IOException {
>>>             // read each input stream until exhaustion
>>>             int r = is.read();
>>>
>>>             boolean goOn = (r == -1);
>>>             while (goOn) {
>>>                 // choose the next one until exhaustion
>>>                 if (urlIt.hasNext()) {
>>>                     is = urlIt.next().openStream();
>>>                     r = is.read();
>>>                     goOn = (r == -1);
>>>                 } else {
>>>                     goOn = false;
>>>                 }
>>>             }
>>>
>>>             return r;
>>>         }
>>>     }
>>>
>>> Then, I simple return the InputRepresentation:
>>> return new InputRepresentation(new CompositeInputStream(urls));
>>>
>>> I hope this will help you.
>>>
>>> Best regards,
>>> Thierry Boileau
>>>
>>>
>>>
>>>
>>>> On Apr 11, 2012, at 2:14 PM, Bjorn Roche wrote:
>>>>
>>>>
>>>> On Apr 11, 2012, at 1:50 PM, Thierry Boileau wrote:
>>>>
>>>> Hi Bjorn,
>>>>
>>>> that's right, I primarily use the restlet 2.1 version, which does not
>>>> support this constructor I think. I'm not sure this has an impact.
>>>>
>>>>
>>>> Well when I use the setter I get the same thing (throws exception) as
>>>> when I pass that value to the constructor.
>>>>
>>>> Also, it looks like the range is being ignored -- I am getting the full
>>>> document back rather than part.
>>>>
>>>>
>>>> By messing with the code you sent, this seems to be a function of
>>>> setting the representation size. If I set the size, it's fine, if not, it
>>>> sends the whole thing regardless of content-range, which seems like a bug.
>>>>
>>>> Can you send me build instructions (pom or ant file?) for your code if
>>>> you have it? I am testing with curl, maybe there is an issue with one of
>>>> our tests?
>>>>
>>>>
>>>> I've figured out how to build (I am an idiot with building)... and I
>>>> can't reproduce the exception.
>>>>
>>>>  bjorn
>>>>
>>>>
>>>> Finally, is it possible to avoid the range processing on just some
>>>> calls for greater efficiency?
>>>>
>>>> bjorn
>>>>
>>>> Best regards,
>>>> Thierry Boileau
>>>>
>>>> Thierry,
>>>>>
>>>>> The first thing I noticed in your code is that you are using the
>>>>> OutputRepresentation constructor that does not take an expectedSize
>>>>> argument, so I took that out and the exception goes away. At the moment my
>>>>> tests are still failing, so I'll look into that some more.
>>>>>
>>>>> bjorn
>>>>>
>>>>> On Apr 11, 2012, at 12:39 PM, Thierry Boileau wrote:
>>>>>
>>>>> Hi Bjorn,
>>>>>
>>>>> I send you a sample test code (server + client) based on your code
>>>>> that works for me. But I notice that my app sends only 15000 bytes... Can
>>>>> you tell us the metrics of your tests?
>>>>>
>>>>> Not 100% sure of the question.. do you mean container? I am not using
>>>>>> jetting. My initialization code looks like this:
>>>>>>                        Component component = new Component();
>>>>>>                        component.getServers().add(Protocol.HTTP,
>>>>>> PORT);
>>>>>>                        component.getDefaultHost().attach(new
>>>>>> com.xonami.rest.server.ApiApplication());
>>>>>>                        component.start();
>>>>>>
>>>>>> Is that what you wanted?
>>>>>>
>>>>> I wanted to know if the application is served using some "server"
>>>>> extensions such as jetty (org.restlet.ext.jetty.jar) or simple
>>>>> (org.restlet.ext.simple.jar), or inside a servlet container.
>>>>>
>>>>>
>>>>> also, in the code I sent it looks like it was not "hanging" but rather
>>>>>> pausing for a moment and then throwing this exception:
>>>>>>
>>>>>> java.io.IOException: Timeout while writing to the queue-based output
>>>>>> stream
>>>>>>        at
>>>>>> org.restlet.engine.io.PipeStream$2.write(PipeStream.java:106)
>>>>>>        at java.io.OutputStream.write(OutputStream.java:99)
>>>>>>        at
>>>>>> com.xonami.rest.server.media.RawMediaStateWithIdResource$1.write(RawMediaStateWithIdResource.java:158)
>>>>>>        at org.restlet.engine.io.BioUtils$2.run(BioUtils.java:394)
>>>>>>        at
>>>>>> org.restlet.service.TaskService$1$1.run(TaskService.java:130)
>>>>>>        at
>>>>>> java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
>>>>>>        at
>>>>>> java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
>>>>>>        at java.lang.Thread.run(Thread.java:680)
>>>>>>
>>>>>
>>>>> thanks, I try to reproduce this error. Or, if may ask you, can you
>>>>> provide a reproductible sample test code?
>>>>>
>>>>> Best regards,
>>>>> Thierry Boileau
>>>>>
>>>>>
>>>>>> -----------------------------
>>>>>> Bjorn Roche
>>>>>> http://www.xonami.com
>>>>>> Audio Collaboration
>>>>>> http://blog.bjornroche.com
>>>>>>
>>>>>> ------------------------------------------------------
>>>>>>
>>>>>> http://restlet.tigris.org/ds/viewMessage.do?dsForumId=4447&dsMessageId=2947368
>>>>>>
>>>>>
>>>>> <testRange.zip>
>>>>>
>>>>>
>>>>>   -----------------------------
>>>>> Bjorn Roche
>>>>> http://www.xonami.com
>>>>> Audio Collaboration
>>>>> http://blog.bjornroche.com
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>>
>>>>   -----------------------------
>>>> Bjorn Roche
>>>> http://www.xonami.com
>>>> Audio Collaboration
>>>> http://blog.bjornroche.com
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>   -----------------------------
>>>> Bjorn Roche
>>>> http://www.xonami.com
>>>> Audio Collaboration
>>>> http://blog.bjornroche.com
>>>>
>>>>
>>>>
>>>>
>>>>
>>>
>>
>

------------------------------------------------------
http://restlet.tigris.org/ds/viewMessage.do?dsForumId=4447&dsMessageId=2949538

Reply via email to