Jump to content
Changes to the Jaspersoft community edition download ×

JasperReport Server Bug? REST PUT to Create Resource Gets "Premature end of file" Exception


dcurry

Recommended Posts

 

I am attempting to create an image type resource in the JasperReport Server 5.1 repository using a PUT to the REST resource web service as described in the Web Services Guide section 2.2.4 Creating a resource. I am using the Spring RestTemplate client to create a multipart request (Content-Type: multipart/form-data) containing the resource descriptor XML (name: ResourceDescriptor, Content-Type: text/plain) in the first part and the resource content as bytes in the second part (name: ReportContent, Content-Type: application/octet-stream). No matter what content I send in the ResourceDescriptor XML, the JasperReport Server returns an HTTP error 400, after emitting an exception message indicating that the Xerces parser encountered a premature end of file while attempting to marshal the resource descriptor.

Here's the exception (the first part of it anyway):

18:31:04,691 ERROR [sTDERR] [Fatal Error] :-1:-1: Premature end of file.18:31:04,693 INFO  [sTDOUT] 2013-08-08 18:31:04,691 ERROR RESTResource,http-0.0.0.0-8080-6:237 - Unexpected error during resource descriptor marshaling: Premature end of file.org.xml.sax.SAXParseException: Premature end of file. at org.apache.xerces.parsers.DOMParser.parse(Unknown Source) at org.apache.xerces.jaxp.DocumentBuilderImpl.parse(Unknown Source) at com.jaspersoft.jasperserver.rest.services.RESTResource.doPut(RESTResource.java:220)[/code]

I've done everything I can think of to ensure that the multi-part form request has been built according to the documentation and that the resource descriptor XML is valid. Here's the tcpdump output of the request (I didn't include the bytes of the application/octet-stream part for the sake of brevity):

18:31:04.686190 IP localhost.53779 > localhost.http-alt: Flags [P.], seq 1:315, ack 1, win 257, options [nop,nop,TS val 65636301 ecr 65636300], length 314E..n.u@.@..................."{.......b.............PUT /jasperserver/rest/resource HTTP/1.1Content-Type: multipart/form-data;boundary=HCu3rqzf5-tNdV9mGtpg88N7MBnTY9rAS6Content-Length: 33508Host: localhost:8080Connection: Keep-AliveUser-Agent: Apache-HttpClient/4.2.1 (java 1.5)Cookie: JSESSIONID=6E2E040261D2C08823BAE8BAAE7AFB00Cookie2: $Version=118:31:04.686216 IP localhost.http-alt > localhost.53779: Flags [.], ack 315, win 256, options [nop,nop,TS val 65636301 ecr 65636301], length 0E..4)@.@.2............."{...........(.............18:31:04.687636 IP localhost.53779 > localhost.http-alt: Flags [.], seq 315:16699, ack 1, win 257, options [nop,nop,TS val 65636301 ecr 65636301], length 16384E.@4.v@.@.vK................"{......>).............--HCu3rqzf5-tNdV9mGtpg88N7MBnTY9rAS6Content-Disposition: form-data; name="ResourceDescriptor"Content-Type: text/plainContent-Length: 728<resourceDescriptor name="JUNIT_IMAGE_FILE" wsType="img" uriString="/SAMPLE_REST_FOLDER/JUNIT_IMAGE_FILE" isNew="true"><label>jaspersoft logo</label><description>jaspersoft logo</description><creationDate>1308696383000</creationDate><resourceProperty name="PROP_RESOURCE_TYPE"><value>com.jaspersoft.jasperserver.api.metadata.common.domain.FileResource</value></resourceProperty><resourceProperty name="PROP_PARENT_FOLDER"><value>/SAMPLE_REST_FOLDER</value></resourceProperty><resourceProperty name="PROP_VERSION"><value>0</value></resourceProperty><resourceProperty name="PROP_IS_REFERENCE"><value>false</value></resourceProperty><resourceProperty name="PROP_HAS_DATA"><value>true</value></resourceProperty></resourceDescriptor>--HCu3rqzf5-tNdV9mGtpg88N7MBnTY9rAS6Content-Disposition: form-data; name="ReportContent"Content-Type: application/octet-streamContent-Length: 32433[/code]

The request looks correct. I've been through the source code of RESTResource.java and BasicResourceCRUDTest.java. I've read the posts in this forum and it seems that a number of people have had this same problem, but no one has come up with a solution. So I'll try my luck.

Does anyone have any idea what's wrong? I'm inclined to believe at this point that it's a bug (or at least some sort of undocumented gotcha) in the REST resource web service.

 
Link to comment
Share on other sites

  • 3 weeks later...
  • Replies 2
  • Created
  • Last Reply

Top Posters In This Topic

Top Posters In This Topic

After much trial and travail and some crucial help from JasperSoft support, I was able to get my use case to work under JasperReport Server 5.2. I thought I would post the answer here in the hope that it may help someone else.

Here's the code to add a content resource (in this case a PDF) to the JasperReport Server repository using the resource REST web service. This code uses the Spring 3.1 RestTemplate:

    public void process(byte[] reportBytes, String fileNameBase) {        // Prepare the ResourceDescriptor XML part        String resourceDescriptor =            "<resourceDescriptor name="TestReport.pdf" wsType="contentResource" uriString="/reports/samples/TestReport.pdf" isNew="false">" + "n" +            "    <label><![CDATA[TestReport.pdf]]></label>" + "n" +            "    <creationDate>1373380817231</creationDate>" + "n" +            "    <resourceProperty name="PROP_RESOURCE_TYPE">" + "n" +            "        <value><![CDATA[com.jaspersoft.jasperserver.api.metadata.common.domain.ContentResource]]></value>" + "n" +            "    </resourceProperty>" + "n" +            "    <resourceProperty name="PROP_PARENT_FOLDER">" + "n" +            "        <value><![CDATA[/reports/samples]]></value>" + "n" +            "    </resourceProperty>" + "n" +            "    <resourceProperty name="PROP_VERSION">" + "n" +            "        <value><![CDATA[0]]></value>" + "n" +            "    </resourceProperty>" + "n" +            "    <resourceProperty name="PROP_SECURITY_PERMISSION_MASK">" + "n" +            "        <value><![CDATA[1]]></value>" + "n" +            "    </resourceProperty>" + "n" +            "    <resourceProperty name="CONTENT_TYPE">" + "n" +            "        <value><![CDATA[pdf]]></value>" + "n" +            "    </resourceProperty>" + "n" +            "    <resourceProperty name="DATA_ATTACHMENT_ID">" + "n" +            "        <value><![CDATA[/reports/samples/TestReport.pdf]]></value>" + "n" +            "    </resourceProperty>" + "n" +            "    <resourceProperty name="PROP_HAS_DATA">" + "n" +            "        <value><![CDATA[true]]></value>" + "n" +            "    </resourceProperty>" + "n" +            "</resourceDescriptor>" + "n";               HttpHeaders descriptorHeaders = new HttpHeaders();        descriptorHeaders.setContentType(new MediaType("text", "plain", Charset.forName("UTF-8")));        descriptorHeaders.set("Content-Transfer-Encoding", "8bit");        HttpEntity<String> descriptorEntity = new HttpEntity<String>(resourceDescriptor, descriptorHeaders);        // Prepare the contentResource binary part               Resource reportResource = new ByteArrayResource(reportBytes) {            @Override            public String getFilename() throws IllegalStateException {                return "TestReport.pdf";            }        };               HttpHeaders resourceHeaders = new HttpHeaders();        resourceHeaders.setContentType(new MediaType("application", "octet-stream", Charset.forName("UTF-8")));        resourceHeaders.set("Content-Transfer-Encoding", "binary");        HttpEntity<Resource> resourceEntity = new HttpEntity<Resource>(reportResource, resourceHeaders);                      // Prepare the multipart form               MultiValueMap<String, HttpEntity<?>> form = new LinkedMultiValueMap<String, HttpEntity<?>>();        form.add("ResourceDescriptor", descriptorEntity);        form.add("/reports/samples/TestReport.pdf", resourceEntity);               HttpHeaders headers = new HttpHeaders();        headers.setContentType(new MediaType("multipart", "form-data"));        HttpEntity<MultiValueMap<String, HttpEntity<?>>> request =                new HttpEntity<MultiValueMap<String, HttpEntity<?>>>(form, headers);               restTemplate.put(getJasperReportsServerUrl() + "/rest/resource/reports/samples/TestReport.pdf", request);    }[/code]

To add a content resource, the resource REST web service requires that the client send a multi-part form in a PUT request with the HTTP header Content-Type "multipart/form-data". This request must consist of two parts:

The first part is the new resource's ResourceDescriptor as an XML string. This part be named "ResourceDescriptor". It must be sent with HTTP headers Content-Type "text/plain; charset=UTF-8" and Content-Transfer-Encoding "8bit". There are requirements for the contents of this resource descriptor, as will be discussed later.

The second part is the binary data for the resource. This part must be named as the path and filename of the resource. It must be sent with the HTTP headers Content-type "application/octet-stream; charset=UTF=8", Content-Transfer-Encoding "binary", and Content-Disposition "filename=<filename>.<ext>" where <filename>.<ext> is the filename of the resource. It was failure to supply this last header that caused the 400 - Bad Request status that was the reason for my original post. It is unintuitive why this should cause a failure to unmarshall the ResourceDescriptor from the XML in the first part, but it does.

In any case, the ResourceDescriptor must contain the attributes and parameters as given in the example or the request will come to grief. In particular, the path and filename given in the request URL, the name and uriString attributes, the PARENT_FOLDER and DATA_ATTACHMENT_ID properties must all be consistent with each other and with the filename attribute of the Content-Disposition header in the second part. Interestingly, the value of the isNew attribute doesn't seem to have any effect on the request.

This is a lot of hoops to jump through, so it's no wonder that so many people have had problems with it.

Link to comment
Share on other sites

Further experimentation has shown that the contentResource part can have a Content-Type that matches the actual type of the resource, not just "application/octet-stream". For example, in my use case I supplied Content-Type "application/pdf; charset=UTF-8" and it worked just fine. You should also be able to supply "image/jpeg; charset=UDF-8" when adding a JPEG image and so forth.

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×
×
  • Create New...