2

I have the following client I am using to call a Jersey REST service.

public class JerseyClient {
    public static void main(String[] args) {
        ClientConfig config   = new DefaultClientConfig();
        Client       client   = Client.create(config);
        WebResource  service  = client.resource(getBaseURI());
        String       response = service.accept(MediaType.TEXT_XML)
                                       .header("Content-Type", "text/xml; charset=UTF-8")
                                       .entity(new File("E:/postx.xml"))
                                       .post(String.class);

        System.out.println(response);
    }

    private static URI getBaseURI() {
        return UriBuilder.fromUri("http://localhost:8080/MyService/rest/xmlServices/doSomething").build();
    }
}

Currently on the server side I have the following:

@POST
    @Path("/doSomething")
    @Consumes(MediaType.TEXT_XML)
    @Produces(MediaType.TEXT_XML)
    public Response consumeXMLtoCreate(ProcessJAXBObject jaxbObject) {

How do I change the above server side code so I can use stAX and stream one particular element to disk instead of converting all into objects into memory. My goal is to stream this element containing binary encoding data to disk.

The payload I receive is like this:

<?xml version="1.0" encoding="utf-8"?> <ProcessRequest> <DeliveryDate>2015-12-13</DeliveryDate>  <AttachmentBinary>iVBORw0KGgoAAAANSUhEUgAAAFoA</AttachmentBinary> <AttachmentBinary>iVBORw0KGgoAAAANSUhEUgAAAFoA</AttachmentBinary> </ProcessRequest>

Following advice from @vtd-xml-author

I now have the following:

Server side:

  @POST
    @Produces(MediaType.TEXT_XML)
    @Path("/doSomething")
    @Consumes(MediaType.APPLICATION_OCTET_STREAM)
    public Response consumeXMLtoCreate(@Context HttpServletRequest a_request,
            @PathParam("fileId") long a_fileId,
            InputStream a_fileInputStream) throws IOException {

        InputStream is;
        byte[] bytes = IOUtils.toByteArray(a_fileInputStream);

        VTDGen vg = new VTDGen();
        vg.setDoc(bytes);
        try {
            vg.parse(false);
        } catch (EncodingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (EOFException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (EntityException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (ParseException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }//
        VTDNav vn = vg.getNav();
        AutoPilot ap = new AutoPilot(vn);
        try {
            ap.selectXPath("/ProcessRequest/BinaryAttachment/text()");
        } catch (XPathParseException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        int i=0;
        try {
            while((i=ap.evalXPath())!=-1){
               //i points to text node of 
               String s = vn.toRawString(i);
               System.out.println("HAHAHAHA:" + s);
              // you need to decode them 
            }
        } catch (XPathEvalException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (NavException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

and client side I have this:

File file = new File("E:/postx.xml");
        FileInputStream fileInStream = null;

            fileInStream = new FileInputStream(file);

        ClientConfig config   = new DefaultClientConfig();
        Client       client   = Client.create(config);
        WebResource  service  = client.resource(getBaseURI());

         String tempImage = myfile.jpg;

        String sContentDisposition = "attachment; filename=\"" + tempImage+"\"";

        ClientResponse response = service.type(MediaType.APPLICATION_OCTET_STREAM)
                                       .header("Content-Disposition", sContentDisposition)
                                       .post(ClientResponse.class, fileInStream);

I have questions that arise from this solution, firstly how exactly am I avoiding the same memory issues if I end up with a String object in heap that I need to decode ?

Secondly can I reconstitute an object or inputStream using vtd-xml once I've removed the image elements as I'd then like to process this using JAXB ?

I believe XMLModifier's remove() method should allow me to have some sort of XML represent minus the element I have now written to disk.

Toby Derrum
  • 299
  • 1
  • 3
  • 22
  • @vtd-xml-author STaX is not a requirement. Any info on how I can implement vtd-xml from the incoming request would be much appreciated. – Toby Derrum Jul 13 '16 at 20:42
  • If you can expand your question by including some XML maybe I can chip in some code snippet maybe? – vtd-xml-author Jul 13 '16 at 20:46
  • @vtd-xml-author thanks, I've just added an XML snippet – Toby Derrum Jul 13 '16 at 20:48
  • @vtd-xml-author: how does stax convert the xml into "all sorts of temporary" objects? – jtahlborn Jul 14 '16 at 01:15
  • String objects, byte array objects, and attribute objects... all sorts of things happen underneath that send those events into your app logics – vtd-xml-author Jul 14 '16 at 01:18
  • if you use the stax streaming api, the overhead is minimal for all but the most extreme performance requirements. working with information in java pretty much requires that you will _eventually_ have a string object representing the element name, etc. – jtahlborn Jul 14 '16 at 01:22

1 Answers1

1

I assume you know how to interface with HTTP protocol in your code..so you know how to read the bytes off the input stream into a byte buffer... the following code will take over from that point ...

public void readBinaryAttachment(HTTPInputStream input) throws VTDException, IOException{
// first read xml bytes into XMLBytes
....
VTDGen vg = new VTDGen();
vg.setDoc(XMLBytes);
vg.parse(false);//
VTDNav vn = vg.getNav();
AutoPilot ap = new AutoPilot(vn);
ap.selectXPath("/ProcessRequest/BinaryAttachment/text()");
int i=0;
while((i=ap.evalXPath())!=-1){
   //i points to text node of 
   String s = vn.toRawString(i);
  // you need to decode them 
}

}
vtd-xml-author
  • 3,319
  • 4
  • 22
  • 30
  • I've updated my question with code based on a rudimentary working example based on your suggestion, although I have further questions as to how this can work with JAXB in Jersey. – Toby Derrum Jul 14 '16 at 14:45