Friday, February 14. 2014
Weaving Problem in EclipseLink
This week I was called because a customer had an issue with EclipseLink and the colleague who usually works there was not in Spain. The problem was a weird one, and it was known, Mingtao explained it in his blog (my problem was inside a WebLogic Server too). The idea is simple: an object is read from the database, the entity manager is closed (so the object is detached), the read object is used as a template to create a new object changing only the ID (the primary key), the new object is merged using another manager. It seems that the specification specifically permits this procedure if the object is detached, but an exception was thrown in the last merge in the customer environment.
Although there was a clear code workaround (just copying the object instead of using the same one read previously) they insisted in knowing what was happening. So I decided to develop a simple test-case with a short entity object. I am going to write down all the steps I did (I consider that not only the solution is important, the process to reach that solution is also crucial):
A Sample entity with just three properties was created:
@Entity @Table(name="SAMPLE") public class Sample implements Serializable { @Id @Column(name = "ID") protected String id = null; @Column(name = "NAME") protected String name = null; @Column(name = "DESCRIPTION") protected String description = null;
A Servlet was developed to reproduce the problem. An initial sample object is read (created if it does not exists), then the manager is closed, in turn, the object detached:
out.println("Obtaining a detached sample..."); Sample s = new Sample(); s.setId("AC98"); em = emf.createEntityManager(); EntityTransaction entityTransaction = em.getTransaction(); entityTransaction.begin(); s = em.find(Sample.class, s.getId()); if (s == null) { out.println("Creating the sample cos it doesn't exist..."); s = new Sample(); s.setId("AC98"); s.setName("AC98"); s.setDescription("AC98"); s = (Sample) em.merge(s); s = em.find(Sample.class, s.getId()); } entityTransaction.commit(); em.close();
Using another manager the same object was merged with a different ID:
s.setId("AC99"); em = emf.createEntityManager(); entityTransaction = em.getTransaction(); entityTransaction.begin(); em.merge(s); entityTransaction.commit(); em.close();
The exception was thrown as expected:
Caused by: Exception [EclipseLink-7251] (Eclipse Persistence Services - 2.5.1.v20130918-f2b9fc5): org.eclipse.persistence.exceptions.ValidationException Exception Description: The attribute [id] of class [es.rickyepoderi.weaving.Sample] is mapped to a primary key column in the database. Updates are not allowed.
I decided to test the same without the server and, to my surprise, it worked. So if the same code was executed using a Java file (same entity and same code, but executed in a main method instead in the processing of the servlet request) the exception was not thrown.
First I thought that it was because of the jdbc resource (obviously in the Java example the EclipseLink was configured to use direct connections, using the driver manager, and inside the application server the persistence unit used a jdbc resource). But I deployed the servlet application using direct connections and it continued failing. It was another thing.
Looking carefully to the logs (the property eclipselink.logging.level was set to ALL) I realized that all the weaving properties were listed as set when using the WLS but they did not appear in the Java example logs. It seems that EclipseLink activates dynamic weaving if it detects a JavaEE container.
The next step was crystal clear. The persistence.xml file was modified disabling all weaving:
<property name="eclipselink.weaving" value="false"/>
And it worked! So the weaving was doing something strange that threw the exception. Checking the properties more carefully I discovered that only one property (eclipselink.weaving.internal) was the guilty one. So finally my little example inside the WLS worked with the following weaving configuration:
<property name="eclipselink.weaving.changetracking" value="true"/> <property name="eclipselink.weaving.lazy" value="true"/> <property name="eclipselink.weaving.eager" value="true"/> <property name="eclipselink.weaving.fetchgroups" value="true"/> <property name="eclipselink.weaving.internal" value="false"/>
I have to say that previously to this week I just know that weaving existed in EcliseLink, I knew it was a performance improvement (recommended for production) but I had no idea what it really was. Looking to EclipseLink documentation, it seems that the purpose of weaving consists of altering Java byte code for adding optimized JPA instructions that include lazy loading, change tracking, fetch groups and internal optimizations. So weaving changes the bytecode of the entity classes to optimize JPA performance (static performs the changes in the real classes, generating new ones, and dynamic performs them at execution time) and, obviously, something wrong was done in internal optimizations for my specific issue.
This morning I had the time to open a public bug against EclipseLink explaining the case (you know I try to be a good neighbor). I modified my external / Java project (weaving-error) to use static weaving, prepared it to execute against derbydb and opened a bug in eclipse bugzilla. In order to statically weave your entity classes you have to execute this java over the resulting jar file (the javax.persistence.jar was obtained from glassfish v4):
java -cp eclipselink-2.5.1.jar:javax.persistence.jar \ org.eclipse.persistence.tools.weaving.jpa.StaticWeave \ -persistenceinfo dist/weaving-error.jar -classpath dist/weaving-error.jar \ -loglevel ALL dist/weaving-error.jar weaving-error.jar
This java process performs the bytecode changes inside the entity classes following the configuration in the persistence.xml provided (in my case the same file of the project). With the resulting jar you can test the bug with this simple command (the derbydb database should be running in the default port):
java -cp weaving-error.jar:javax.persistence.jar:eclipselink-2.5.1.jar:derbyclient.jar \ es.rickyepoderi.weaving.Test
The bug is clear, if you perform the static weaving with internal activated, the exception is thrown. If your weaving is configured to do all optimizations except the internal ones, the test runs without problems. I saw a lot of references of this problem during the day I spent in the customer but no one explained the issue in detail and, of course, no one commented the problem was due to weaving (everybody changed the JPA implementation). It was a complicated day for sure. I hope that now, with this entry and the bug reported in EclipseLink, nobody wastes more time on this.
See you!
Saturday, February 8. 2014
RTC Data Channels
Today's entry is again about the Web Real Time Communication (WebRTC), the new API to enable P2P video and audio between browsers. In two previous entries the WebRTC demo application was presented (python web application developed by google and mozilla in order to test their respective implementation and the interoperability between them) and then the sample application was modified to use glassfish 4 instead of python as the server (glassfish 4 was chosen because it has the WebSocket implementation standardized by JavaEE 7). In this third entry of the series a new concept is going to be introduced: RTC Data Channels.
Obviously in a common WebRTC use (audio and video communication) there are specific data channels to send and receive the steaming audio and video information, but the specification provides a way to obtain a general purpose P2P bi-directional data channel to send whatever information. Obviously WebRTC tries to replace any previous communication application and this type of channels are absolutely necessary (sending files, chat applications,...). Here you have a very detailed link about data channels in bloggeek.me if further information is needed.
I started testing this feature using the following simple application. It is a simple html file which creates two RTCPeerConnection and establishes a data channel between them for sending text and files. The same page represents both ends (the sender and the receiver). The code is prepared to work with chrome but with minimal changes it can also be tested with firefox.
After testing with the previous and simple example, I decided to enhance my glassfish application in order to create a chat system. Now there is a new chat.xhtml page which creates the RTC data channels (the RTCPeerConnection is established in the same way as before). The channel is used to send the messages between the peers. The application works well inside my home network between two firefox browsers (iceweasel 24.2 or current firefox 26.0) and chromium (31.0.1650.63) but it does not work when the browsers are mixed. When the channel is opened in one side the callback at the other side is not triggered, so the connection is never established when the browsers are different. The little application can also exchange files between the peers but the file is transmitted as a single chunk, that produces errors when the file is big enough. If you recheck the previous link from bloggeek.me there is a maximum transmission data size in chrome and if the file is too big errors are displayed (it seems that firefox supports bigger chunks but problems are also reported).
Although the application is very simple and a bit sloppy, it is a good example of a RTC data channel. Here it is a video where two browsers inside the same laptop connect using the glassfish apprtc application and start chatting. The process is exactly the same than in the video example: one user connects to the page and remains there waiting for the other partner to join; the second user connects to the same URL (same room); the negotiation starts using the glassfish server as intermediary; when the peer connection is established a data channel between them is created; then chatting and exchanging files can proceed.
Some time ago I presented some entries about integrating VOIP in a portal (skype first and then an opensource pidgin solution), if you recheck the current series about WebRTC, now it is possible to replace the previous off-browser idea with a browser-only solution. The current implementation and the specification itself is not mature, WebRTC should be fully implemented by the major browsers and the interoperability should be assured, but the apprtc application, although simple and sloppy, is the perfect proof that all the required features are covered by the specification (video, audio, chat, exchanging files,...). The browser is the VOIP device and the server (glassfish in my example) is just a way of making the peers know each other. I suppose that sooner than later some JS projects will appear implementing a fully WebRTC device or, at least, making WebRTC easier to integrate in a final project. Here you have the modified apprtc project for glassfish with the chat page integrated.
Readapting an old slogan: the browser is the computer.
Comments