Binary Data and GWT

There are already a couple of questions about binary data and GWT. After reading it, I'm still not sure if the following is possible or not (I'm new to GWT, though!):

I have very complex data files that exist only in binary form, and I cannot convert them to something like XML or JSON. I have a closed source library, although it takes bytes [] and returns a Java object that I can use. To run my GWT application, I “printed out” one of these binary data files and encoded the received byte [] in a .java file that I get from my GWT application code. Everything is working fine. Obviously, this is just a test, and in a deployed application I cannot hard-code these data files. I want to put them in the directory of my GWT application and download it with my GWT application.

I understand that I can download text files from my server using GWT, right? Why can't I read binary data using GWT? Or can I read binary data files as text and String in bytes []? I read a lot about base64 encoding and that GWT can read it, although I don’t quite understand what they are talking about. Can I configure my server to serve these base64 encoded binary data and then read it using GWT?

Or is there another solution? I would not want to touch any JS code if I can help him. This is why I started using GWT;)

Thank you for your help:)

+2
source share
4 answers

Suppose we are in HTML 4.

GWT client cannot read files. The GWT client is javascript running in the browser. Browser security does not allow you to read local files. You must force the proxy servlet to read the file for you on the server.

You set the mime type for the file because you want the browser to download the file and call the local computer to invoke the appropriate software - for example, pdf to invoke a PDF reader or xls to invoke ms excel. Nothing to do with GWT Java or Javascript (other than to enable loading).

Why do you need a GWT client to read a binary file? If you do, your architecture is probably wrong. "Wrong" is an unkind word. Perhaps the wrong is the best word. Your AJAX Thin Client Server concept is incorrect. Leave your desktop handling concepts and door habits when you enter the GWT door.

GWT is Java, but not Java

I have to remind people all the time that GWT Java is just a more consistent view of Javascript. When you code in GWT Java, always remember that you actually code in Javascript, not Java. All Java source translated into Javascript

Therefore, the GWT compiler needs all the Java classes that will be delivered in the source code. The GWT compiler is not able to translate Java bytecode jar / class files into Javascript. If your library is in bytecode or your source library calls the bytecode library anywhere in the call chain, compilation will fail.

Confusion between server side and GWT client side

GWT RPC is sometimes a source of confusion for GWT beginners. They do not seem to understand that the remote servlet is the only part that is compiled into bytecode because it runs on the server. Especially if you use Vaadin - because they so deliberately blurred the line between the server and the browser. So, the GWT newbie wonders: "Why do my bytecode libraries work only in some parts of the application?"

Ajax client server architecture

GWT is just a web-based interface. Why can't you do what you want to do on the server and let the server reflect what it does or did with the user interface? Why should this be done in a browser?

Imagine your GWT interface is a crazy JSP. Imagine you are writing JSP. Are you getting your JSP to suck your binary data in the browser and get the JSP to generate Javascript to parse the binary data there?

I wrote complex statistical analyzes, and I just used the browser as a reflection of what is being done on the server. The engineer believes that he / she conducts the analysis on his PC. Charts / reports are created. But all this is done on the server, causing SAS.

Service Oriented Template / Architecture

Your server will provide services. Your browser The GWT client will request these services. Open the file, read the file, analyze the file, create a visual / mime representation of the analysis and transfer it to the browser. Just think of the GWT browser client as a monitor monitor for management on the server. GWT is a magical trick that will help me evoke the illusion that engineers feel like they are analyzing on a local PC. Of course, engineers, many of whom know that the browser is actually not doing its job.

When your user is satisfied with the analysis, get your service to generate a MIME presentation of the results so that it can be downloaded by the browser to invoke the corresponding local PC software displayed using mime.

Do it on the server and mirror it in the browser.

Additional changes . As for binary data ...

Base64 encoding motivation used in web applications: transferring auth tokens, images, audio files - so that their binary representation and sequence will not be spoiled by architectural nuances such as endianness.

For example, do not try to write a browser application to read the raw binary table - always translate the server into XML or JSON (preferably JSON), where any binary element must be encoded in base64 before sending it to the browser application. Or, if the goal of your life is to climb Mount Everest, come up with architectural-agnostic coding instead of base64 to transmit binary data.

Use only binary information if it was for processing the browser OS (for example, audio, images, pdf files). It makes no sense to pass binary data just for javascript processing. The javascript procedure would have to use extraneous processing time to translate it (if, again, if the goal in your life is to rise ...).

+5
source

Yes it is possible.

Two solutions depending on the data type.

  • Dynamic (if binary data is dynamic and may change):
    Base64 simply encodes your binary data on your server and serves it (i.e. a GET request). You can then use any of the GWT communication protocols (see here for more details) to retrieve data from the backend.
    Then you will need to base64 decode the data and work with it (as you already decided).

  • Static (if binary data will not change and are known at compile time):
    You can use the ClientBundle ( i.e .: DataResource) to generate these binaries at compile time, and then they can be automatically restored on the client side without manually configuring their migration.

+4
source

Client side:

@Override public void onModuleLoad() { RequestBuilder rb = new RequestBuilder(RequestBuilder.GET, "/test"); try { rb.sendRequest(null, new RequestCallback() { @Override public void onResponseReceived( Request request, Response response ) { String encoded = response.getText(); byte[] data = decode(encoded); System.out.println(Arrays.toString(data)); } @Override public void onError( Request request, Throwable exception ) { } }); } catch( RequestException e ) { e.printStackTrace(); } } private final static String base64chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; public static byte[] decode( String s ) { // remove/ignore any characters not in the base64 characters list // or the pad character -- particularly newlines s = s.replaceAll("[^" + base64chars + "=]", ""); // replace any incoming padding with a zero pad (the 'A' character is // zero) String p = (s.charAt(s.length() - 1) == '=' ? (s.charAt(s.length() - 2) == '=' ? "AA" : "A") : ""); s = s.substring(0, s.length() - p.length()) + p; int resLength = (int) Math.ceil(((s.length()) / 4f) * 3f); byte[] bufIn = new byte[resLength]; int bufIn_i = 0; // increment over the length of this encrypted string, four characters // at a time for( int c = 0; c < s.length(); c += 4 ) { // each of these four characters represents a 6-bit index in the // base64 characters list which, when concatenated, will give the // 24-bit number for the original 3 characters int n = (base64chars.indexOf(s.charAt(c)) << 18) + (base64chars.indexOf(s.charAt(c + 1)) << 12) + (base64chars.indexOf(s.charAt(c + 2)) << 6) + base64chars.indexOf(s.charAt(c + 3)); // split the 24-bit number into the original three 8-bit (ASCII) // characters char c1 = (char) ((n >>> 16) & 0xFF); char c2 = (char) ((n >>> 8) & 0xFF); char c3 = (char) (n & 0xFF); bufIn[bufIn_i++] = (byte) c1; bufIn[bufIn_i++] = (byte) c2; bufIn[bufIn_i++] = (byte) c3; } byte[] out = new byte[bufIn.length - p.length()]; System.arraycopy(bufIn, 0, out, 0, out.length); return out; } 

Server Side (Java):

 @Override public void doGet( HttpServletRequest request, HttpServletResponse response ) throws ServletException, IOException { byte[] binaryData = new byte[1000]; for( int i = 0; i < 1000; i++ ) binaryData[i] = (byte) (Byte.MIN_VALUE + (i % (Math.pow(2, Byte.SIZE)))); System.out.println("Sending: " + Arrays.toString(binaryData)); byte[] base64Encoded = org.apache.commons.codec.binary.Base64.encodeBase64(binaryData); response.setContentType("application/octet-stream"); PrintWriter out = response.getWriter(); out.write(new String(base64Encoded)); } 
+2
source

Here you can read bytes from any URL easily:

  XMLHttpRequest request = XMLHttpRequest.create(); request.open("GET", "http://127.0.0.1:8888/sample/index.bin"); request.setResponseType(ResponseType.ArrayBuffer); request.setOnReadyStateChange(new ReadyStateChangeHandler() { @Override public void onReadyStateChange(XMLHttpRequest xhr) { if (xhr.getReadyState() == XMLHttpRequest.DONE) { if (xhr.getStatus() == 200) { ArrayBuffer buffer = xhr.getResponseArrayBuffer(); Uint8Array array = TypedArrays.createUint8Array(buffer); System.out.println("got " + array.length() + " bytes: "); for (int i = 0; i < array.length(); i++) { System.out.println(array.get(i)); } } else { System.out.println("response status: " + xhr.getStatus() + " " + xhr.getStatusText()); } } } }); request.send(); 
0
source

Source: https://habr.com/ru/post/1445543/


All Articles