vaadin-component-factory / vcf-pdf-viewer-flow

Vaadin Addon for providing pdf viewing functionality
Apache License 2.0
9 stars 6 forks source link

Invalid data structure - but Download works fine #10

Closed florianrhomberg closed 1 year ago

florianrhomberg commented 2 years ago

Hello, if I try to open a PDF I get using CMIS with Apache chemistry with a Stream Resource handler I get the mentioned error. However if I open the PDF using the EmbeddedPDf viewer it works excepted usind Edge. However downloading the PDF file works fine and I can open the downloaded file with any pdf viewer.

  1. Getting the PDF using Apache Chemistry and writing it into a FileRecord: ` public static FileRecord getDocumentAsFileRecord(CmisClient client, String objectId) throws IOException { Document document = getDocument(client, objectId); if(document != null) {

        InputStream stream = document.getContentStream().getStream();
        byte[] byteEncoded = Base64.getEncoder().encode(IOUtils.toByteArray(stream));
    
        FileRecord record = new FileRecord();
        record.setFile(byteEncoded);
        record.setFilename(document.getName());
        record.setFiletyp(document.getContentStream().getMimeType());
        record.setDeleted(false);
        record.setCreationDate(Date.from(document.getCreationDate().toZonedDateTime().toInstant()));
        record.setSize(document.getContentStream().getStream().readAllBytes().length);
        record.setCmisId(objectId);
        return record;
    }
    return null;

    } `

  2. Create the Stream resource of the file record: ` public static StreamResource getStream(final FileRecord record) { InputStreamFactory factory = new InputStreamFactory() { @Override public InputStream createInputStream() { return new ByteArrayInputStream(record.getFile()); } };

    StreamResource resource = new StreamResource(record.getFilename(), factory);
    resource.setContentType(record.getFiletyp());
    return resource;

    } `

  3. Combining both methods and creating an instance of the PdfViewer: ` private void createPdfViewer() { this.removeAll();

    //
    // This is working:
    //
    EmbeddedPdfDocument pdf = new EmbeddedPdfDocument(StreamResourceHandler.getStream(record));
    pdf.setSizeFull();
    //this.add(pdf);
    
    //
    // This fails with "Invalid Data structure
    //
    PdfViewer viewer = new PdfViewer();
    viewer.setSrc(StreamResourceHandler.getStream(record));
    viewer.setSizeFull();
    this.add(viewer);

    } `

The PDF is not displayed. Hopefully somone can help me, thanks, Florian

probert94 commented 2 years ago

I am facing a similar issue and was able to find the reason for it. The pdf-viewer stops working, as soon as you have a path with at least one segment, which ends with a "/". So if you access the pdf-viewer with localhost:8080/test it works, if you access it with localhost:8080/test/ it gives the error "Invalid PDF structure". Checking the network tab you can see, that without the trailing "/", it requests the pdf at "http://localhost:8080/VAADIN/dynamic/resource/5/e5b03283-446d-4ef4-8f78-b2f0338008bf/example.pdf", while with trailing "/" it uses "http://localhost:8080/test/VAADIN/dynamic/resource/6/855dcd49-f3c7-4432-ae36-7131119418ff/example.pdf". In my case I have a route with URL-Parameters, so I always have at least one path segment and the pdf-viewer therefor never works in my case.

probert94 commented 2 years ago

My current workaround is to register a custom RequestHandler which checks if the current URI contains the dynamic resource prefix and if thats the case, it searches for the specific dynamic resource. I the resource is the one the PdfViewer should show, it will handle it using the StreamResourceHandler.

return (VaadinSession session, VaadinRequest request, VaadinResponse response) -> {
  String pathInfo = request.getPathInfo();
  int idx = Strings.indexOfIgnoreCase(pathInfo, StreamRequestHandler.DYN_RES_PREFIX);
  if (idx > 0) {
    String resourcePath = pathInfo.substring(idx);
    session.lock();
    try {
      if (getPathUri(resourcePath)
        .flatMap(session.getResourceRegistry()::getResource)
        .filter(resource -> resource == src)
        .isPresent())
      {
        new StreamResourceHandler().handleRequest(session, request, response, src);
        return true;
      }
    }
    finally {
      session.unlock();
    }
  }
  return false;
};
paodb commented 2 years ago

Could you give it a try with latest version 2.0.2?

probert94 commented 2 years ago

Seems to work with 2.0.2, thank you