I usually write technical articles here. This article is an exception. I do not know if this is a checked exception or not though. I do not even know if this really is an exception or rather an error or just something throwable. (I am just fooling around with the different Java exception types only because I am such a fun guy and also because this is a Java blog, so it SHOULD, as defined in rfc2119, have some words about Java.)
This article is about how I create video tutorials. I have created a few. Not many. The implication of the amount is that what I tell you here is not the ultima ratio. I am almost sure that in many things I am wrong and I am open to criticism. Just be polite: a few people actually read this blog, including the comments.
I created screen video recording as product documentation when I was running my own company ten years ago. I also created some as a training for my current employer, EPAM, and also for this blog and for PACKT. (Yes, this part of the article is a commercial, please go and subscribe and learn Java 9 new features from me listening to Java 9 New Features Deep Dive [Video].)
Length
The length of a video should be 5 to 10 minutes. The shorter the better. I was worried at first about not being able to fill these time frames. But it is easy. I usually struggle with the opposite. Sometimes I can not make the video as short as I would like to.
Presentation
Many times I create a presentation to highlight what I will talk about during the demonstration. This is important. These visuals help the audience get the content and understand what they can expect in the coming five or ten minutes. In other cases, the presentation itself is the main attraction. I usually use Microsoft PowerPoint simply because that is what I have the most experience with and it is available both on Windows and OSX.
Screen Recording
I use OSX and iShowU Instant. I record video in HD format these days and I also use an external monitor attached to my mbp. The recording control is on the built-in display of the mbp, which is a bit higher resolution than HD and the recorded scene is running on the external screen.
I record applications maximized and if possible set to full screen. There is no reason to show the little “minimize, maximize, close” icons or the application frame. This is equally true on OSX, Linux or Windows.
When you do something on the screen do not explain it while doing it. Explain it before and then do it. The reason for that is that this way the keyboard and mouse noise is separated from the talk and can be muted. Also, when you type silently you have the option later while editing the video to speed up the typing. The audience gets bored seeing how the typed letters come up one after the other. You can simply speed it up for a longer typing ten times even. They will see that this is sped up, but that is not a problem unless you want to demonstrate the speed of something.
Voice Recording
I live in a little, peaceful Swiss dorf (village). The road is near and the airplanes landing to Kloten (ZRH) just fly above the house, so the voice recording environment is not ideal, but around 10pm it is acceptable. In my former (Budapest) location, I could not record without noise. So the first thing is that you need a very quiet environment. Perhaps this is the most costly investment, but it also serves other purposes: it boosts your sleep, irons your nerves. Peace is invaluable, world peace… you know.
When you consider the noise, do not only rely on your ears. I have a neighbor who is a professional drum player. Switzerland has strict noise regulation and these guys living here mean it: he is using some special drum set that suppresses the sound a lot. I am 52 and it means my hearing started to slowly decay. I would not have noticed that he is playing the drum sometimes till 11pm (which is strictly illegal, you can do the noisy activity until something like 8pm) unless I started recording. The microphone was recording it and I could hear it in the headset attached to the mic.
I also realized through the headset that the table and the chair is a huge source of the noise. PACKT supports content creators (at least they supported me) with some PDFs that give some very practical technical advice and the chair was mentioned there. Table was not. Do not lean on the table when recording. Better yet, do not even touch it.
The second important thing is the microphone. I tried to use the built-in mic of my MacBook Pro, which is exceptionally good for things like Skype, ad-hoc recording, recording a meeting, but not sufficient for tutorial recording. I bought an external microphone for 28CHF but it was not good enough. It was noisy. The one that I finally found is sufficient is a Zoom H2n recorder that also works as a USB microphone.
It stands on my desk on a tripod. I usually put a pillow between the mic and the notebook, so the noise of the vent is dumped and I also moved the external HDD under the table. The pillow thing was coming from one of the PACKT materials and it is a great idea: it works and it is simple. The HDD now stands on the floor on a cork wood base (originally it was some IKEA cooking thing) which is put on top of a thick, folded (multiple times) cloth. Even though the noise of it is almost inaudible I disconnect it when I do the recording. That also prevents a backup firing off while recording eating the CPU off from the screen recorder, which itself is not a CPU hog to my surprise, but that is a different story. Here we talk about the noise (sic) recording. Btw: while recording also disable the network, unless you want to demonstrate something that needs it. You do not want to record notification popups.
While I talk I attach a BOSE Q25 headset directly to the mic and through that I hear my own voice amplified. Because you hear your own voice from inside through your bones when you talk it sounds totally different when you listen to the recording. With the headset, the voice leaving my mouth is amplified and with active noise cancellation, I hear myself more from outside only through the microphone. It helps me to articulate better and also to recognize when my tongue twists.
Talking
I had to realize that I have to talk slow. I mean really slow. And as far as I know, most people who record voice run in the same shoe. When you record something, slow down your talk and when you feel that this is ridiculously slow then it probably is just okay.
When your tongue twists or you just realize that you made a mistake in a sentence: do not correct the part like you would do in a live presentation. Stop. Take a breath. Think. Wait 5 seconds or more. Take your time and restart from the start of the last, erroneous sentence. The 5 seconds helps you to think about where to restart from, but this is also something easy to notice on the waveform when the recorded video is edited. If there is a pause in the voice it probably is something to cut off. I also hit the table with my palm, which makes a noise overloading the microphone and is a clearly visible peak on the waveform. You can also clap your hands or use a whistle. May seem ridiculous first.
Recording face
You may want to record your face while you talk about some slides. This is good for the audience, it makes your presentation more personal. I use an external webcam for this purpose. Although iShowU Instant can put the video input on the recorded screen as a picture in the picture, I decided to record the video input separately. On OSX I can record simultaneous screen using iShowU and the video input using PhotoBooth. That way both inputs will have the same audio recorded from the same microphone. This helps to put the two videos in sync when editing and then one of the audio (presumably the one from the presentation, as it is the one less sensitive to slipped audio) can be deleted.
This way it is also possible to put the PIP face at different locations although I do not recommend that you move it a lot around. But it can many times be removed from the screen. For example, if you record slides as well as demo code then you can show your talking head on the slides and hide it when showing code demo on the screen.
When you talk you have to face the camera. It is difficult because you want to talk about a slide that is not in the camera. It is on a screen that is just at the side of the camera. The bad news is that the audience will see that you are not looking into their eyes (which is the camera). You HAVE TO look into the camera.
I was told to look at the slide, read it and then look into the camera and say the text again and then cut it off during the editing phase. It did not work. What worked was that I created a teller machine from a cardboard box, picture glass, and black paint. I also bought for something like 5$ a teller application that runs on my iPad and is reflected from the glass, which is set 45 degrees in front of the webcam. It all stands on a tripod on the table.
Video Background
I use a curtain behind my chair to have an ambient background. There is nothing wrong with a room in the background, but it may cause some problems.
A clock on the wall will show that you recorded the video in several steps. It will jump back and forth and it is distracting for the audience. It is also bad when some background items, chairs, tables, etc. jump between different cuts of the video.
Video Editing
To edit the video I use iMovie. This comes free with the operating system on a mac and has enough functionalities to edit a technical video. Sometimes I feel I lack some features, which are available in professional video editing software products but later I realize that I do not need them.
I value the Kern Burns cropping functionality very much. This was originally invented to show still pictures in a dynamic, moving way in a movie. When doing screen capture I can use this functionality to move the focus to the area of the screen, (usually showing the IDE when programming Java) that is important from the demo point of view.
Takeaway
There are many ways of doing tutorial videos, and I cannot tell what will fit your personality, topic, and audience. I wrote down my experience and I hope you can find something useful in it for you.
When you have a class inside another class they can see each others private methods. It is not well known among Java developers. Many candidates during interviews say that private is a visibility that lets a code see a member if that is in the same class. This is actually true, but it would be more precise to say that there is a class that both the code and the member is in. When we have nested and inner classes it can happen that the private member and the code using it is in the same class and at the same time they are also in different classes.
As an example, if I have two nested classes in a top-level class then the code in one of the nested classes can see a private member of the other nested class.
It starts to be interesting when we look at the generated code. The JVM does not care about classes inside other classes. It deals with JVM “top-level” classes. The compiler will create .class files that will have a name like A$B.class when you have a class named B inside a class A. There is a private method in B callable from A then the JVM sees that the code in A.class calls the method in A$B.class. The JVM checks access control. When we discussed this with juniors somebody suggested that probably the JVM does not care the modifier. That is not true. Try to compile A.java and B.java, two top-level classes with some code in A calling a public method in B. When you have A.class and B.class modify the method in B.java from being public to be private and recompile B t a new B.class. Start the application and you will see that the JVM cares about the access modifiers a lot. Still, you can invoke in the example above from A.class a method in A$B.class.
To resolve this conflict Java generates extra synthetic methods that are inherently package private, call the original private method inside the same class and are callable as far as the JVM access control is considered. On the other hand, the Java compiler will not compile the code if you figure out the name of the generated method and try to call in from the Java source code directly. I wrote about in details more than 4 years ago https://javax0.wordpress.com/2014/02/26/syntethic-and-bridge-methods/.
If you are a seasoned developer then you probably think that this is a weird and revolting hack. Java is so clean, elegant, concise and pure except this hack. And also perhaps the hack of the Integer cache that makes small Integer objects (typical test values) to be equal using the == while larger values are only equals() but not == (typical production values). But other than the synthetic classes and Integer cache hack Java is clean, elegant, concise and pure. (You may get I am a Monty Python fan.)
The reason for this is that nested classes were not part of the original Java, it was added only to version 1.1 The solution was a hack, but there were more important things to do at that time, like introducing JIT compiler, JDBC, RMI, reflection and some other things that we take today for granted. That time the question was not if the solution is nice and clean. Rather the question was if Java will survive at all and be a mainstream programming language or dies and remains a nice try. That time I was still working as a sales rep and coding was only a hobby because coding jobs were scarce in East Europe, they were the mainly boring bookkeeping applications and were low paid. Those were a bit different times, the search engine was named AltaVista, we drank water from the tap and Java had different priorities.
The consequence is that for more than 20 years we are having slightly larger JAR files, slightly slower java execution (unless the JIT optimizes the call chain) and obnoxious warnings in the IDE suggesting that we better have package protected methods in nested classes instead of private when we use it from top-level or other nested classes.
Nest Hosts
Now it seems that this 20-year technical debt will be solved. The http://openjdk.java.net/jeps/181 gets into Java 11 and it will solve this issue by introducing a new notion: nest. Currently, the Java bytecode contains some information about the relationship between classes. The JVM has information that a certain class is a nested class of another class and this is not only the name. This information could work for the JVM to decide on whether a piece of code in one class is allowed or is not allowed to access a private member of another class, but the JEP-181 development has something more general. As times changed JVM is not the Java Virtual Machine anymore. Well, yes, it is, at least the name, however, it is a virtual machine that happens to execute bytecode compiled from Java. Or for the matter from some other languages. There are many languages that target the JVM and keeping that in mind the JEP-181 does not want to tie the new access control feature of the JVM to a particular feature of the Java language.
The JEP-181 defines the notion of a NestHost and NestMembers as attributes of a class. The compiler fills these fields and when there is access to a private member of a class from a different class then the JVM access control can check: are the two classes in the same nest or not? If they are in the same nest then the access is allowed, otherwise not. We will have methods added to the reflective access so we can get the list of the classes that are in a nest.
Simple Nest Example
Using the
$ java -version
java version "11-ea" 2018-09-25
Java(TM) SE Runtime Environment 18.9 (build 11-ea+25)
Java HotSpot(TM) 64-Bit Server VM 18.9 (build 11-ea+25, mixed mode)
version of Java today we can make already experiments. We can create a simple class:
package nesttest;
public class NestingHost {
public static class NestedClass1 {
private void privateMethod() {
new NestedClass2().privateMethod();
}
}
public static class NestedClass2 {
private void privateMethod() {
new NestedClass1().privateMethod();
}
}
}
Pretty simple and it does nothing. The private methods call each other. Without this the compiler sees that they simply do nothing and they are not needed and the byte code just does not contain them.
The class to read the nesting information
package nesttest;
import java.util.Arrays;
import java.util.stream.Collectors;
public class TestNest {
public static void main(String[] args) {
Class host = NestingHost.class.getNestHost();
Class[] nestlings = NestingHost.class.getNestMembers();
System.out.println("Mother bird is: " + host);
System.out.println("Nest dwellers are :\n" +
Arrays.stream(nestlings).map(Class::getName)
.collect(Collectors.joining("\n")));
}
}
The printout is as expected:
Mother bird is: class nesttest.NestingHost
Nest dwellers are :
nesttest.NestingHost
nesttest.NestingHost$NestedClass2
nesttest.NestingHost$NestedClass1
Note that the nesting host is also listed among the nest members, though this information should be fairly obvious and redundant. However, such a use may allow some languages to disclose from the access the private members of the nesting host itself and let the access allow only for the nestlings.
Byte Code
The compilation using the JDK11 compiler generates the files
NestingHost$NestedClass1.class
NestingHost$NestedClass2.class
NestingHost.class
TestNest.class
There is no change. On the other hand if we look at the byte code using the javap decompiler then we will see the following:
$ javap -v build/classes/java/main/nesttest/NestingHost\$NestedClass1.class
Classfile .../packt/Fundamentals-of-java-18.9/sources/ch08/bulkorders/build/classes/java/main/nesttest/NestingHost$NestedClass1.class
Last modified Aug 6, 2018; size 557 bytes
MD5 checksum 5ce1e0633850dd87bd2793844a102c52
Compiled from "NestingHost.java"
public class nesttest.NestingHost$NestedClass1
minor version: 0
major version: 55
flags: (0x0021) ACC_PUBLIC, ACC_SUPER
this_class: #5 // nesttest/NestingHost$NestedClass1
super_class: #6 // java/lang/Object
interfaces: 0, fields: 0, methods: 2, attributes: 3
Constant pool:
*** CONSTANT POOL DELETED FROM THE PRINTOUT ***
{
public nesttest.NestingHost$NestedClass1();
descriptor: ()V
flags: (0x0001) ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 6: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this Lnesttest/NestingHost$NestedClass1;
}
SourceFile: "NestingHost.java"
NestHost: class nesttest/NestingHost
InnerClasses:
public static #13= #5 of #20; // NestedClass1=class nesttest/NestingHost$NestedClass1 of class nesttest/NestingHost
public static #23= #2 of #20; // NestedClass2=class nesttest/NestingHost$NestedClass2 of class nesttest/NestingHost
If we compile the same class using the JDK10 compiler, then the disassembles lines are the following:
$ javap -v build/classes/java/main/nesttest/NestingHost\$NestedClass1.class
Classfile /C:/Users/peter_verhas/Dropbox/packt/Fundamentals-of-java-18.9/sources/ch08/bulkorders/build/classes/java/main/nesttest/NestingHost$NestedClass1.class
Last modified Aug 6, 2018; size 722 bytes
MD5 checksum 8c46ede328a3f0ca265045a5241219e9
Compiled from "NestingHost.java"
public class nesttest.NestingHost$NestedClass1
minor version: 0
major version: 54
flags: (0x0021) ACC_PUBLIC, ACC_SUPER
this_class: #6 // nesttest/NestingHost$NestedClass1
super_class: #7 // java/lang/Object
interfaces: 0, fields: 0, methods: 3, attributes: 2
Constant pool:
*** CONSTANT POOL DELETED FROM THE PRINTOUT ***
{
public nesttest.NestingHost$NestedClass1();
descriptor: ()V
flags: (0x0001) ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #2 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 6: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this Lnesttest/NestingHost$NestedClass1;
static void access$100(nesttest.NestingHost$NestedClass1);
descriptor: (Lnesttest/NestingHost$NestedClass1;)V
flags: (0x1008) ACC_STATIC, ACC_SYNTHETIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method privateMethod:()V
4: return
LineNumberTable:
line 6: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 x0 Lnesttest/NestingHost$NestedClass1;
}
SourceFile: "NestingHost.java"
InnerClasses:
public static #14= #6 of #25; // NestedClass1=class nesttest/NestingHost$NestedClass1 of class nesttest/NestingHost
public static #27= #3 of #25; // NestedClass2=class nesttest/NestingHost$NestedClass2 of class nesttest/NestingHost
The Java 10 compiler generates the access$100 method. The Java 11 compiler does not. Instead, it has a nesting host field in the class file. We finally got rid of those synthetic methods that were causing surprises when listing all the methods in some framework code reflective.
Hack the nest
Let’s play a bit cuckoo. We can modify the code a bit so that now it does something:
package nesttest;
public class NestingHost {
// public class NestedClass1 {
// public void publicMethod() {
// new NestedClass2().privateMethod(); /* <-- this is line 8 */
// }
// }
public class NestedClass2 {
private void privateMethod() {
System.out.println("hallo");
}
}
}
we also create a simple test class
package nesttest;
public class HackNest {
public static void main(String[] args) {
// var nestling =new NestingHost().new NestedClass1();
// nestling.publicMethod();
}
}
First, remove all the // from the start of the lines and compile the project. It works like charm and prints out hallo. After this copy the generated classes to a safe place, like the root of the project.
Now we have a NestingHost that knows that it has only one nestling: NestedClass2. The test code, however, thinks that there is another nestling NestedClass1 and it also has a public method that can be invoked. This way we try to sneak an extra nestling into the nest. If we execute the code then we get an error:
$ java -cp build/classes/java/main/ nesttest.HackNest
Exception in thread "main" java.lang.IncompatibleClassChangeError: Type nesttest.NestingHost$NestedClass1 is not a nest member of nesttest.NestingHost: current type is not listed as a nest member
at nesttest.NestingHost$NestedClass1.publicMethod(NestingHost.java:8)
at nesttest.HackNest.main(HackNest.java:7)
It is important to recognize from the code that the line, which causes the error is the one where we want to invoke the private method. The Java runtime does the check only at that point and not sooner.
Do we like it or not? Where is the fail-fast principle? Why does the Java runtime start to execute the class and check the nest structure only when it is very much needed? The reason, as many times in the case of Java: backward compatibility. The JVM can check the nest structure consistency when all the classes are loaded. The classes are only loaded when they are used. It would have been possible to change the classloading in Java 11 and load all the nested classes along with the nesting host, but it would break backward compatibility. If nothing else the lazy singleton pattern would break apart and we do not want that. We love singleton, but only when single malt (it is).
Conclusion
The JEP-181 is a small change in Java. Most of the developers will not even notice. It is a technical debt eliminated and if the core Java project does not eliminate the technical debt then what should we expect from the average developer?
As the old Latin saying says: “Debitum technica necesse est deletur.”
Update
Brian Goetz 2018-09-06 on https://dzone.com/articles/nesting-java-classes :
“You theorize that the motivation for the lazy check is compatibility, but there is a much simpler explanation: this is yet another example of Java’s pervasive commitment to dynamic linkage. References to other classes and class members are only checked for validity and accessibility when they are actually needed, such as when a method is called, or a class is extended. This is just more of the same — nothing new here.”
The new version of the HTTP protocol, HTTP/2 lets the server to push content to the client before the client requests the particular content. There are many other modifications in the protocol if we compare the previous version 1.1 with the new version 2, but in this article, I will focus on the push functionality. I will discuss briefly how it can be used in a servlet, and I will also discuss a bit about how to test and see that it really works at all or not. Before writing this article my original intention was to create a demonstration of HTTP/2 showing how faster the sample page load is with the push than it is without. It is going to be one chapter in my video tutorial that is published by PACKT. During the development of the sample application I faced several problems, I have read some tutorials and debugged the sample code a bit gathering experience. In this article, I share this experience with you. That way this article is a bit more than just a simple introductory tutorial. Nevertheless, it is also a bit longer, so TLDR; if you are impatient.
HTTP versions
HTTP/2 is a new version of the HTTP protocol. The protocol had three versions prior to 2. They were 0.9, 1.0 and 1.1. The first one was only an experiment starting in 1991. The first real version was 1.0 released in 1996. This was the version that you probably met if you were using the internet that time and you still remember the Mosaic browser. This version was soon followed by the version 1.1 next year, 1997. The major difference between 1.0 and 1.1 was the Host header field that made it possible to operate several websites on one machine, one server, one IP address, and one port.
HTTP 1.1
Both versions 1.0 and 1.1 are extremely simple. The client opens a TCP channel to the server and writes the request into it as a plain text. The request starts with a request line, it is followed by header lines, an empty line and the body of the request. The body may be binary. The response has the same structure except the first line is not a request specific line, but rather a response obviously.
Imho, the simple approach was extremely important these days because it was inevitable to aid the spread and use of the protocol. You can find this type of pattern in the industry in different areas. This is how the world is developing in an agile way. First, you develop something simple that works and then you go on making it more and more complex as the environment requires it to be more powerful longing for more complexity. Making a long-shot and aiming for the complex and perfect solution the first time usually does not work. If you remember the film series Star Wars you know that death stars are never finished and they are razed at the end. But it does not mean that the simple version that we start with has no problems.
HTTP/1.1 problems
HTTP/1.1 had a lot of problems. A real Englishman could say it was far from optimal using the network. It was wasting bandwidth. Early times when HTTP was invented a web page was text. Today it is text, CSS, JavaScript, images, sounds, videos and digitized smell, taste, and touch samples not to mention the direct neural stimulation command files. These last content types following videos in this taxative list are still rare but you should be prepared and that is what HTTP/2 is aiming. Preparing for the future. With HTTP/1.1 the browser downloads these resources one after the other in separate TCP channels. The number of the TCP channels the server or for that matter the client can handle is finite, therefore the browsers limit themselves not to open more than four TCP channels. It means that while four content elements for the page is downloading the other elements wait in a queue to be downloaded. If we have some very slow downloading content it may choke the download of the whole web page. You can run experiments with that writing some simple servlet that sends a complex HTML page to the browser and then you let some of the content elements download slow and others fast. Doing it in debug mode using Chrome you will get a nice Gantt chart of the download timings.
The network is also wasted creating a new TCP channel for each new HTTP connection. Creating a TCP channel require an SYN package traveling from the client to the server, then an SYN-ACK from the server to the client and then an ACK from the client to the server again before we can start sending data. In addition to these, the TCP protocol limits itself not to flood a lossy channel with a lot of data that is going to be lost anyway, so it starts slow, sending only a few data packages at the start and increases the speed only when it sees that packages are arriving in good shape and content. Let’s just think about that three-way handshake that starts the TCP channel. The network between the client and the server has a certain lag and has a certain bandwidth. The lag is the time needed for a package to travel from the client to the server or the other way around. The bandwidth is the number of bits that can be pushed through the network between the client and the server during a given time (like one second). Imagine a hose that you use to fill buckets. If it is long it may take two or three seconds until the water starts to pour after you opened the tap. If it is narrow filling a bucket can take a minute. In that case, 2-3 seconds at the start is not a big deal, you have to wait a minute anyway. On the other hand, if the hose is wide the water may run in amount filling the bucket in ten seconds. Three seconds delay is 30%. It is significant. Similarly the TCP channel slow-start lag is significant in fast networks, where the bandwidth is abundant. Fortunately, we go in this direction. We get fibers in our homes replacing the 19.2kbps dial-up modems. However, at the same time, HTTP/1.1 lag is an increasing problem.
There is a header field Keep-alive that can tell the server not to close the TCP channel, but rather reuse it for the next HTTP request and this patch on the scar of HTTP/1.1 helps a lot, but not enough. The blocking slow resource problem is still there. There are other problems with HTT/1.1 that HTTP/2 addresses but this, using many TCP channels to download several content pieces to the client from the same server is the main issue related to server push, which is indeed the topic of this article.
HTTP/2
HTTP/2 uses a single TCP channel between the server and the client. When the content is downloaded from different servers the client will eventually open separate TCP channels to each server, but for the content pieces that come from the same server, HTTP/2 uses only one TCP channel. Using multiple TCP channels between a certain client and a single server does not speed up the communication, it was only a workaround in HTTP/1.1 to partially mitigate the choking effect of slow resources.
A request and a corresponding response do not use exclusively the TCP channel in HTTP/2. There are frames and the request and the response travels in these frames. If a content piece is created slowly and does not use the channel for some time then other resources can get frames and can travel in the same TCP channel. This is a significant boost of download speed in many cases. The change is also transparent for the browser programs being either JavaScript or WebAssembly. In the case of WebAssembly, the change is extremely simple: WebAssembly does not directly handle XMLHttpRequest, it uses JavaScript implemented and imported functions. In the case of JavaScript, the browser hides the transport complexity. JavaScript network API is just the same as it was before. You request a resource, you get one and you do not need to care if that was traveling in its exclusive TCP channel, mixed into HTTP/2 frames or was sent to you by pigeon post. On the server side, the approach is the same. In case of Java, a servlet application gets a request and creates a response. It is up to the container, the web server and to the client browser how they make it travel through the net.
The only difference, where server application may change is server push. This is a new feature and the new API gives an extra possibility for a server application to initiate a content push to the client.
When to Push, What to Push?
The server push typically can be used in a situation when the application prepares some content slowly and the application knows that this is going to be slow and it also knows that there are other resources, typically many small icon images that can be downloaded fast and will be needed by the client. Thus the conditions for the server push are (PRECONDITIONS)
the content requested is slow,
the application knows it is going to be slow,
there are other resources that will be needed by the client after this resource was downloaded,
the application knows what these resources are,
these resources can be downloaded fast.
In this case, the servlet can initiate one or more push that may deliver the content to the browser while the main content is prepared. When the main content is ready, and the client browser realizes that it needs the extra resources they are already there. If we do not push the resources they will be downloaded only after the original resource was processed when the browser realizes that the extra resources are needed. In a simple example, when the browser sees all the img tags and knows that it needs the icon images to render the page. This is what the above animation tries to show in a simple way.
How to push
To initiate a push it is more than simple. The servlet standard 4.0 extends the HttpServletRequest to create a new PushBuilder whenever the servlet calls req.newPushBuilder() on the request object req. The push builder can be used to create a push and then invoking the method push() on it will initiate the sending towards the client. It is as simple as that. The only parameter that you have to set is the path of the resource to be pushed.
var builder = req.newPushBuilder();
...
builder.path(s).push();
Sample application
The sample application to test server push is a servlet that responds with an HTML page that contains one hundred image references in a 10×10 table. Essentially these are small icons from the http://www.flaticon.com website
The first thing the servlet does is to initiate the icon downloads via server push. To do that it creates one push builder and this single object is used to initiate 100 pushes. After that, the servlet goes to sleep. This sleep simulates the slow inner working of the servlet response. A real application in this time would gather the information needed to send the response from the different database, from other services and so on. During this time the server and the client have enough time to download the PNG files. When the response arrives the files are there and the images are displayed instantaneously. At least that is what we expect.
The servlet has a parameter, named push that can be 1 or 0. If this parameter is 1 the servlet pushes the PNG files to the client, it is 0 then it is not. This way we can easily compare the speed of the two different behaviors.
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
final String titleText;
var builder = req.newPushBuilder();
var etag = now();
if (builder == null) {
titleText = "Good old HTTP/1.1 download";
} else {
var pushRequested = parse(req).get("push", 1) == 1;
if (pushRequested) {
titleText = "HTTP/2 Push";
sendPush(req, builder, etag);
} else {
titleText = "HTTP/2 without push";
}
}
var lag = parse(req).get("lag", 5000);
var delay = parse(req).get("delay", 0);
var sleep = new ThrottleTool.Sleeper();
sleep.till(lag);
resp.setContentType("text/html");
sendHtml(req, resp, titleText, etag, delay, sleep);
}
The servlet can also be parametrized with query parameters lag and delay.
lag is the number of milliseconds the servlet sleeps counting from the start of the servlet before it starts to send the HTML page to the client. The default value is 5000, which means that the HTML sending will start 5seconds after the servlet started.
delay is the number of milliseconds the servlet sleeps between each image tags. The default value is zero, that means the servlet sends the HTML as fast as it can send.
For the push, it is interesting how we get the builder object. The line
var builder = req.newPushBuilder();
returns a new builder object that can also be null. It is null if the environment does not allow push. The simplest case is when the servlet is queried through normal HTTP and not HTTPS. HTTP/2 works only over TLS secure channel and that way if we open the servlet via HTTP it will not be able to push anything.
After this, the method sendPush() sends the push contents as the name implies. Here is the method:
private void sendPush(HttpServletRequest req, PushBuilder builder, long etag) {
for (var i = 0; i < 10; i++) {
for (var j = 0; j < 10; j++) {
var s = imagePath(i, j, req, etag);
builder.path(s);
builder.push();
}
}
}
The method imagePath() calculates the relative URL for the png based on the indices and this path is specified through the push builder. The builder is finally asked to push the content. This call to push() initiates the push on the server.
The builder is used literally one hundred times in this example. We do not need new builder objects for each push. We can safely reuse the same objects. The only requirement is that we set all the parameters before the next push we need. This is usually only the path.
Image Server
The icon images are not directly served by the server in the demo application. The URL for the icon resources is mapped to a servlet that reads the icon PNG from the disk and writes it to the response. The reason for it is twofold. The chronologically first reason is that during the application debugging I needed information when and how the resource is collected and in case the resource is just a plain file that the server directly handles I do not have many possibilities to debug or log anything. The second reason is that the demo needs network throttling. Just as in case of the main HTML resource that waits 5 seconds before it vomits out the HTML text images also need to slow down to show a good demonstration effect. There is a throttling functionality in the debug mode of the browsers. However, it seems that this throttling in Chrome is architecturally between the cache where the pushed resources are temporarily stored and the DOM displaying engine. Implementing throttling on the demo server in our code is certainly at a good place from the experiment point of view and it can not happen that the already pushed and downloaded resource is loading throttled into the screen.
For this reason, the image servlet has two query parameters. imglag is the number of milliseconds the servlet waits after a hit arrives and before it starts to do anything. The default value in case the parameter is missing is 300 milliseconds. The other parameter is imgdelay that specifies the number of milliseconds the server consumes sending the bytes of the image to the client. This is implemented in a way that the server sends each byte individually one after the other and in case the current time is proportionally too soon to serve the next byte then the server sleeps a bit. The default value is 1000, which means that each icon is delivered from the server in approximately 1.3sec. The code itself is not too educational from the server push point of view. You can see it in the GitHub repository https://github.com/verhas/pushbuilder/blob/master/src/main/java/javax0/pushbuilder/demo/ImageServer.java
PushBuilder methods
The PushBuilder class has many other methods in case you need to build a request that has some special characteristics. When you initiate the push of a resource you actually define an HTTP request, for which the resource would be the answer. The actual resource is provided by the server. If it is a normal static resource, like an image then the server will pick it up from the file system. If it is some dynamically calculated resource, then the server will start the servlet that is targeted by the request. What the push builder really builds up is a request that stays and is used on the server and the client will actually never issue this request after the resource was already pushed. The setter methods of the class set request attribute, like parameters, headers etc.
method()
You can set the method of the request that the resource is a response to. By default, this is GET and this should be OK most of the time. If the resource is a response to a POST, PUT, DELETE, CONNECT, OPTIONS or TRACErequest then we can not push the resource anyway because the HTTP/2 standard does not allow resources of those kinds to be pushed. What remains is the HEAD method that does not seem to be meaningful. I believe that the method method() is in the interface
for compatibility reason if ever there will be some new method,
for the sake of some application that uses some proprietary non-standard method
or as a joke (a method called method).
sessionId()
This method can be used to set the session id that is usually carried in the JSESSIONID cookie or in a request parameter.
set, add and remove + Header()
You can modify the header of the request using these methods. When you invoke setHeader() the previous value is supposed to be replaced. The addHeader() adds a new header. When you reuse the same object adding the same header again and again may result the same header in the request multiple times. Finally the removeHeader() removes a header.
Note that some tutorials also add the header Content-type and the value in some of the tutorials is image/png. This is erroneous even though it does not do any harm. The headers we set on the push builder are used to request the resource. In our example, the images are not directly accessed by Tomcat, but rather are delivered through a servlet. This servlet reads the content of the PNG file from the disk and sends it to the writer that it acquires from the response object. This servlet will see the headers set in the push builder. If we set the content type to be image/png, it may think that we do are a special kind of stupid sending an HTTP GET request body that is PNG format. Usually, it does not matter, servlets and servers tend to ignore the content type for GET request especially when the content has zero bytes. What format does a non-existent picture have?
get methods
What you can set on the push builder object you can also get out. You can use these getHeader(), getMethod(), getHeaderNames(), getPath() and so on methods to see what the current value of the values is in the push builder.
Experiments
During the experiments, I could not see any difference between HTTP/2 with and without the push. The download using HTTP/2 was inevitably faster than HTTP/1.1, but there was no difference between the push and the non-push version. I used Chrome Version 67.0.3396.99 (Official Build) (64-bit). The browser supports the push functionality but the developer tools do not support the debugging of the push. Pushed contents are displayed as normally downloaded contents. There is some secret internal URL (well, not really a secret since it is published on the net), that will show the actual frames, but it is not too handy. What I could see there finally, that the push itself worked. The images were pushed to the browser while the main HTML page serving servlet was having its 5 seconds sleep, but after that, the browser was just downloading the images again, even if I switched on browser caching.
Since HTTP/2 was started by SPDY protocol and it was pushed by Google (pun indented (again)) I strongly believed that it is my code that does something wrong. Finally, I gave up and fired up a Firefox and here you go, this is what you can see on the screen captures:
Summary Takeaway
Server push is an interesting topic and a powerful technology. There are a lot of preconditions to use it (see listed above, search for “PRECONDITIONS”). If these are all met then you can think about implementing it, but you should do experiments with the different network setups, delays and with the different client implementations. If the client implementation is less than optimal then you may end up with a slower download with a push than without one. There is a lot of room for development in the clients. Some of these developments will just mature the way the browsers handle server pushed resource, but I am almost sure that soon we will also have JavaScript API that may register call-back functions to be triggered when a push starts so that it will not only be the browser autonomously who can refuse a push stream but also the client-side JavaScript. Keep the eyes and your mind open for the development of HTTP/2.
This looks like a pretty nasty bug actually. The fact that this is Java 9 onwards and only spotted now does make me question how many people are using Java 9 in production and how safe it is to migrate to it.
— Richard Warburton🥓 (@RichardWarburto) June 6, 2018
If you look at the twitter thread you can see that following this tweet I had some friendly fencing-bout with Nicolai Parlog about upgrading or not upgrading to non-LTS Java versions for commercial production applications (what a Shakespearian dilemma!). Part of the bouts was about misunderstandings as usually when using a limited communication channel. (Just a side note: I know Nicolai irl, he publishes a lot, a nice guy, great Java expert and in case you follow me on the blog, twitter or just in the street you definitely should also follow him, .. better not in the street, that is creepy.)
Since Twitter is a bit short of characters I decided to collect here my thoughts.
What is the question at all?
For a lot of people, who use a computer and support themselves, install new software the question is obvious: use the latest version! Why would anyone want to use an outdated version of a software? I do not say that their answer is wrong for the situation they are in, but it is not a rationally calculated decision. You can decide based on rations or based on feelings or even random. Your decision may be sufficiently good, though science says that decisions based on well-established reasoning are usually more reliable and more often sufficiently good than other decisions. That is the reason why there are so many divorces.
The well-established reasonings about the upgrades and when to upgrade consider the cost and the benefit of the upgrade. What costs do we have?
Costs and benefits
The first and most obvious cost item of the software upgrade is the installation cost: .
It may be small but it can also be significant when the organization has several servers. The installation has to be tested. The new version of the software may not be compatible with the previous version from which we upgrade and it has to be tested. Proof of the pudding is eating. The testing should be done on the actual application that we use. For example, we may not care about the bug that falsely calculates an x += value expression if our code never uses the += operator. The testing cost is .
The benefit , the reason we do the upgrade is that the software runs better and thus it produces more income for the company and/or needs less maintenance cost .
The summing up should be considered from the time of the installation until the time while the software is used.
Assumptions, simplifications
In case of a Java version upgrade, it is extremely difficult to know the and the best estimate is to model it as zero. That essentially leads us to cost reduction. Estimating the cost reduction we usually ignore the short-term effects and consider only the long-term ones. Using Java 9 instead of Java 8 in a short time period rather increases than decreases the support costs. The support people have to learn the small intricacies of the new version and they are likely to make more mistakes shortly after the upgrade. This is essentially a temporary increase that we could consider to be part of the upgrade cost. In real life, if ever these calculations are performed these costs are not identified and do not get an estimated value. Rather they are ignored lessening the detected cost of an upgrade. This is understandable if you consider that these cost estimations are made by IT people and we love the newest versions and we want to upgrade. (As a demonstration read the Twitter thread.)
In the long run, when we consider the in the range of 5 to 10 years the maintenance cost is drastically increasing. A few years ago an old friend of mine was offered a year-long contract to maintain RPG application (not the role-playing game, google it, it eas before COBOL) for 400EUR per hour and he refused saying that the little time he has left he wants to spend with the family. (Old I meant literally in his case.) You cannot find a developer who would joyfully jump on the possibility to maintain a Java 6 application and if they accept they will not be shy to ask the price. You will see the same moue on their face when you mention that time age-old Java 8 or Java 9 version.
That means that the part is estimated as infinite for large values and zero for small ones. In layman terms, it implies that sooner or later we have to upgrade. Upgrade necesse est. Vivere non est necesse.
What we have left is the cost of the upgrade .
Upgrade cost
When we consider Java long term and non-long term support versions we have to compare the small steps upgrade process and the three stairs jump climbing from one LTS to the next LTS version.
Every upgrade cost has a constant part . This is the cost of downloading the media, installing on the server, running the tests, managing the meetings, communicating the out-of-service times and so on.
There is another part of the cost that depends on the previous version from which we upgrade, a variable part of the cost . When you upgrade from Java 8 to Java 9 you have to fight each and every compatibility issue that affects your application. Say this is . Similarly, you will have and .
The big question is
?
It is certain that the variable part of the cost of the upgrade from Java 8 to Java 11 is larger than the same adding up from Java 8 to Java 9 and then from Java 9 to Java 10 and from Java 10 to Java 11. Using the notation for the difference
the above question becomes simpler and easier to interpret:
Interpretation and conclusion
The calculation mainly is playing around with latex and mathematical expressions, and they result in the obvious: if the constant cost of the upgrade that happens three times in one case versus one time in the other case is bigger than the extra cost of the big leap upgrading from Java 8 to Java 11 then you should not upgrade to the intermediate versions. If you work in a big organization with a lot of meetings, lot of administration, which is needed to keep the organization alive, then you do not upgrade for each an every version. If you are a small company, doing things fast and flexible then you will upgrade.
Post Scriptum
Creating the formulas and expressing the calculation in a mathematicized way helps engineers to avoid some mistakes like ignoring some cost that should not be.
Do not think that being small, flexible and fast is always better than big, slow. Both have advantages and disadvantages and both have the place to live in the economy. A small company will never build a railway, a telecom network, or an ocean cruiser. The dinosaurs are extinct but there are whales as well as viruses. You may certainly enjoy more to work for a virus than for a whale.
I have edited the video I recorded during the conference where I presented Comparing Golang and Understanding Value Types. The conference was DevDays Vilnius, the talk was May 24, 2018. The video shows the slides and, just for the sake of completeness and to increase the enjoyment factor, my slender myself presenting in PIP.
I delivered the talk also April, the same year in Mainz at W-JAX and it seems that this talk is doomed. In Mainz, another talk finished sooner and the presenter’s wireless mic was on the same frequency as mine. They forgot to switch it off and coming closer to our room the noise of the coffee break mixed with the signal of my mic.
Here in Vilnius, there was a presentation in the room next to my presentation where apparently there was no air conditioning and all doors and mobile walls were kept open all times. The presentation delivered by Sam Bellen was titled “Channel Your Inner Rockstar with the WebAudio API”. Don’t laugh! It was not funny!
Comparing Golang and understanding Java Value Types
The talk compares the memory model of the Go programming language to the memory model of Java. This comparison will help Java developers understand the planned Java 10 feature: Value Types. The talk will describe how these are implemented in Go, and why they so much needed for the Java language. At the end of the presentation, the audience will also understand why Value Types cannot be extended, immutable and passed always by value.
This talk is very lucrative for the audience because it is about Go language as well as a future of the upcoming Java version that is not available yet. Both are a gem for the audience.
Before Java 9 there was a lot of room to do tricky things mainly using reflection. Some of these possibilities were even considered as security holes. With the advent of Java 9, the module systems close these secret doors in Java runtime library and also allows library developers to do the same for their libraries.
The presentation will demonstrate some shocking and funny examples what you could do using Java 8 and then tries to do the same obviously failing using Java 9.
This article talks about WebAssembly and can be read to get the first glimpse of it. At the same time, I articulate my opinion and doubts. The summary is that WebAssembly is an interesting approach and we will see what it will become.
Java in the Browser, the past
There was a time when we could run Java applets in the browsers. There were a lot of problems with it, although the idea was not total nonsense. Nobody could tell that the future of browser programmability is not Java. Today we know that JavaScript was the winner and the applet as it is deprecated in Java 9 and is going to be removed from later Java versions. This, however, does not mean that JavaScript is without issues and it is the only and best possible solution for the purpose that a person can imagine.
JavaScript has language problems, there are a lot of WTF included in the language. The largest shortage, in my opinion, is that it is a single language. Developers are different and like different languages. Projects are different best solved by different programming languages. Even Java would not so immensely successful without the JVM infrastructure supported by so many different languages. There are a lot of languages that run on the JVM, even such a crap as ScriptBasic.
Now you can say that the same is true for the JavaScript infrastructure. There are other languages that are compiled to JavaScript. For example, there is TypeScript or there is even Java with the GWT toolkit. JavaScript is a target language, especially with asm.js. But still, it is a high level, object-oriented, memory-managed language. It is nothing like machine code.
Compiling to JavaScript invokes the compiler once, then the JavaScript syntax analyzer, internal bytecode and then the JIT compiler. Isn’t it a bit too many compilers till we get to the bits that are fed into the CPU? Why should we download the textual format JavaScript to the browser and compile it into bytecode each time a page is opened? The textual format may be larger, though compression technologies are fairly advanced, and the compilation runs millions of times on the client computer emitting a lot of carbon into the air, where we already have enough, no need for more.
(Derail: Somebody told me that he has an advanced compression algorithm that can compress any file into one bit. There is no issue with the compression. Decompression is problematic though.)
WebAssembly
Why can’t we have some bytecode based virtual machine in the browser? Something that once the JVM was for the applets. This is something that the WebAssembly guys were thinking in 2015. They created WebAssembly.
WebAssembly is a standard program format to be executed in the browser nearly as fast as native code. The original idea was to “complement JavaScript to speed up performance-critical parts of web applications and later on to enable web development in other languages than JavaScript.” (WikiPedia)
Today the interpreter runs in Firefox, Chromium, Google Chrome, Microsoft Edge and in Safari. You can download a binary program to the browser and you can invoke it from JavaScript. There is also some tooling supporting developing programs in “assembly” and also on higher level languages.
Structure
The binary web assembly contains blocks. Each block describes some characteristics of the code. I would say that most of the blocks are definition and structure tables and there is one, which is the code itself. There is a block that lists the functions that the code exports, and which can be invoked from JavaScript. Also, there is a block that lists the methods that the code wants to invoke from the JavaScript code.
The assembly code is really assembly. When I started to play with it I had some nostalgic feeling. Working with these hex codes is similar to programming the Sinclair ZX80 in Z80 assembly when we had to convert the code manually to hex on paper and then we had to “POKE” the codes from BASIC to the memory. (If you understand what I am talking about you are seasoned. I wanted to write ‘old’ but my editor told me that is rude. I am just kidding. I have no editor.)
I will not list all the features of the language. If you are interested, visit the WebAssembly page. There is consumable documentation about the binary format.
There are, however, some interesting features that I want to talk about to later express my opinions.
No Objects
The WebAssembly VM is not an object-oriented VM. It does not know objects, classes or any similar high-level structures. It really looks like some machine language. It has some primitive types, like i32, i64, f32, f64 and that it is. The compiler that compiles high-level language has to use these.
No GC
The memory management is also up to the application. It is assembly. There is no garbage collector. The code works on a (virtually) continuous memory segment that can grow or shrink via a system call and it is totally up to the application to decide which code fragment uses which memory address.
Two Stacks
There are two stacks the VM works with. One is the operation stack for arithmetic operations. The other one is the call stack. There are functions that can call each other and return to the caller. The call sequence is stored in a stack. This is a very usual approach. The only shortage is that there is no possibility to mark the call stack and purge it when an exception happens. The only possibility to handle try/catch programming structure is to generate code before and after function calls that check for exception conditions and if the exception is not caught on the caller function level then the code has to return to the higher level caller. This way the exception handling walks through the call stack with the extra generated code around each function call. This slows down not only the exception handling but also the function calls.
Single Thread
There is no threading in WebAssembly.
Support, Tooling
The fact that most of the browsers support WebAssembly is one half of the bread. There have to be developer tools supporting the concept to have code that can be executed.
There is an LLVM backed compiler solution so technically any language that is compiled to LLVM should be compilable to WebAssembly and run in the browser. There is a C compiler in the tooling and you can also compile RUST to WebAssembly. There is also a textual format in case you want to program directly in assembly level.
Security
Security is at least questionable. First of all, WebAssembly is binary, therefore it is not possible, or at least complex to look at the code and analyze the code. The download of the code does not require channel encryption (TLS) therefore it is vulnerable to MITM attack. Similarly, WebAssembly does not support code signature that would assert that the code was not tampered with since being generated in the (hopefully protected) development environment.
WebAssembly runs in a sandbox, just like JavaScript or like Flash was running. Fairly questionable architecture from the security point of view.
WebAssembly was developed for to years to reach a Minimal Viable Product (MVP) that can be used as a PoC. There are features, like garbage collection, multi-thread support, exception handling support, SIMD type instructions, DOM access support directly from WebAssembly, which are developed after MVP.
Present and Future
I can say after playing like a weekend with WebAssembly that it is an interesting and nice toy. In its current state, it is a toy, nothing more. Without the features planned after MVP, I see only one viable use case: WebAssembly is the perfect tool to deploy malicious mining code on the client machines. In addition to that, any implementation flaw in the engine is a security risk. Note that these security risks come from a browser functionality that gives no value to the average user. You can disable WebAssembly in some of the browsers. It is a little worrisome that it is enabled by default, although it is needed only for early adopters for PoC and not commercial projects. If I were paranoid I would say that the browser vendors, like Google, have a hidden agenda with the WebAssembly engine in the browser.
I am afraid that we see no security issues currently with WebAssembly only because technology is new and IT felons have not learned yet the tools. I am almost certain that the security holes are currently lurking in the current code waiting to be exploited. Disable WebAssembly in your browser till you want to use it. Perhaps in a few years (or decades).
The original aim was to amend JavaScript. With the features after MVP, I strongly believe that WebAssembly will rather aim to replace JavaScript than amend it. There will be a time when we will be able to write applications to run in the browser in Golang, Swift, Java, C, Rust or whatever language we want to. So looking at the question in the title “will Java get back to the browser?” the answer is definitely NO. But some kind of VM technology, JIT, bytecode definitely will sometime in the future.