tag:blogger.com,1999:blog-77879056515273456062023-11-16T12:00:26.695+01:00Developer thoughtsGabor Farkashttp://www.blogger.com/profile/15102167846333868896noreply@blogger.comBlogger17125tag:blogger.com,1999:blog-7787905651527345606.post-1020150279296655652013-05-08T15:32:00.000+02:002013-05-08T15:34:15.136+02:00Hyper-V, ICS, RRAS NAT and port-forwarding on Windows Server 2012<div dir="ltr" style="text-align: left;" trbidi="on">
With some friends we bought a quite strong computer and set up Window Server 2012 with Hyper-V virtualized machines for our projects. Computing power is much cheaper this way than in notebooks, so we can use lighter notebooks to be generally used as portable remote terminals. It works out quite well. RDP can be used well over 3G too.<br />
<div>
<br /></div>
<div>
However we started to face network problems on the server. At first, the computer was located on a company site, so the network configuration looked like this:</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiwpqHXPNOO0EqFkNYpPAZedKSNLOmjrx3WwrzWGGPVKdpbYaDvJXew3qD81dN9rQbSmw2tve8f9lTUPijjto4p1TaezUvQZXyVKSqQGad8mZUfgijUWN_noKo6IuNBpmSEeDR-TEL19-Q/s1600/Untitled+Diagram.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="372" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiwpqHXPNOO0EqFkNYpPAZedKSNLOmjrx3WwrzWGGPVKdpbYaDvJXew3qD81dN9rQbSmw2tve8f9lTUPijjto4p1TaezUvQZXyVKSqQGad8mZUfgijUWN_noKo6IuNBpmSEeDR-TEL19-Q/s640/Untitled+Diagram.gif" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
This required no special configuration, everything just worked as it should. The host machine and the VMs got an internal IP address from the router. To access VMs from the internet, we added port forwarding on the router.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<h3 style="text-align: left;">
Internal Switch</h3>
<div>
Then we decided to put the host machine to a server hosting room with a dedicated IP address. That required us to change the network configuration, as the External Switch would no longer work without a router in front of it.</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEik5sSobMBKDNqzB3ivMENOwb2XLeXSohHiy0PL5S4zX85lSnYID6nWF3U1K31udcHnseICn-wRicgfFbLW0ysWa2SFNF0LhGY3r_ErBkFiXf2H-_NtPkBa3Aq2mawf1hIGe4pnL8cVMbM/s1600/Config+with+internal+switch.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="450" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEik5sSobMBKDNqzB3ivMENOwb2XLeXSohHiy0PL5S4zX85lSnYID6nWF3U1K31udcHnseICn-wRicgfFbLW0ysWa2SFNF0LhGY3r_ErBkFiXf2H-_NtPkBa3Aq2mawf1hIGe4pnL8cVMbM/s640/Config+with+internal+switch.gif" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
With the Internal Switch the virtual machines share a virtual network that can also be accessible from the host machine. To have internet on the VMs, you have to set up NAT.</div>
<h4 style="text-align: left;">
Internet Connection Sharing</h4>
<div class="separator" style="clear: both; text-align: left;">
Our very first try of configuration</div>
<div class="separator" style="clear: both; text-align: left;">
1. The primary NIC has a fix IP address with fix gateway and DNS.</div>
<div class="separator" style="clear: both; text-align: left;">
2. The NIC has Internet Connection Sharing turned on:</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhSXre28w4-TpPEzpEYFTw2gfDsHdC0XyO6Ofgozb_CXX9pvNLLB3qSLG7Ksupg1tXHTILLouzycYd4EnGzEuLOqf_EGtdKOzeqOY-Y8fOqIgcQCJ6OjKDYwYLdWHj9p0GkzrlNZdJkkwk/s1600/ICS.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhSXre28w4-TpPEzpEYFTw2gfDsHdC0XyO6Ofgozb_CXX9pvNLLB3qSLG7Ksupg1tXHTILLouzycYd4EnGzEuLOqf_EGtdKOzeqOY-Y8fOqIgcQCJ6OjKDYwYLdWHj9p0GkzrlNZdJkkwk/s320/ICS.png" width="252" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
If the "Home networking connection" combobox doesn't appear, don't worry. If there's only one other elegible connection, then it's unshown.</div>
<div class="separator" style="clear: both; text-align: left;">
When you click OK, the Internal Switch should be configured to 192.168.137.1/255.255.255.0</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Havin this done, and having the internal switch assigned to the VMs, the VMs should now properly have internet connection without any further configuration. They get IP addresses like 192.168.137.x and 192.168.137.1 as gateway. If they don't, try disabling and enabling the internal switch, or configure them (while running) to have no network (Not connected), then configure them to use Internal Switch again. These might help.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
If you want to open an RDP session to a VM, click Settings on the ICS screen above and add a rule:</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgjNXLtwTfuHQYtcd9NpHNVGyXKLbiAlTCZJ-g9y8oWbKXqC3wV7b1TgFNbo7QvdaCvjJLWZer2ccrJw1GMhcaDqog73u7zh4qFaalUsqtr7CeTJLnQWdP78Nkdnwx9aaJv7nTyvJwpRyk/s1600/ICSportforward.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="286" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgjNXLtwTfuHQYtcd9NpHNVGyXKLbiAlTCZJ-g9y8oWbKXqC3wV7b1TgFNbo7QvdaCvjJLWZer2ccrJw1GMhcaDqog73u7zh4qFaalUsqtr7CeTJLnQWdP78Nkdnwx9aaJv7nTyvJwpRyk/s320/ICSportforward.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
Also make sure to enable inbound connections on the port 3390 of the host machine. Now you can open an RDP session on hostmachine:3390 and it will be forwarded to the VM. Of course, also make sure to enable remote access on the VM.</div>
<div class="separator" style="clear: both; text-align: left;">
When testing this, make sure to open the connection from the outside internet. As I've found it in a random blog post, ICS doesn't route port forwarding from the intranet, so if you try hostmachine:3390 from the hostmachine itself, it probably won't work, but if you try from 'outside', it will.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
This solution can work, but has some drawbacks:</div>
<div class="separator" style="clear: both; text-align: left;">
</div>
<ul style="text-align: left;">
<li>The settings above sometimes just does not work. I haven't yet figured out what to restart and in what order, but sometimes you just have to reconfigure the entire thing. Enablind and disabling the Internal Switch, detaching and reattaching it to the VM, disabling and enabling ICS are options you can perform in any order.</li>
<li>Altought network connection over NAT is just as fast as the host connection, RDP over the port forwarding is unusably slow. I've found some forum posts about how to make it faster (NIC interface configurations) but they didn't work for me.</li>
<li>In some constellation, if I connect to a VM, it asks me for my credentials, but then the screen remains blank. Also my concurrent RDP connection to the host hangs up. After some 20 seconds the VM RDP connection closes and the host connection resumes. If this happens, try reconfiguring everything.</li>
<li>After rebooting the system I usually ended up losing RPD connectivity to the host machine. Every other thing worked: RDP to the VMs and even http worked on the host machine (apache server). To prevent this I had to explicitly add a port forwarding from hostmachine:3389 to 127.0.0.1:3389. Weird.</li>
</ul>
<div>
Also, at my first try the network connection to have packets lost. If I enabled ICS, the host RDP session only worked for 10 seconds, then hanged for another 10, then it took 10 seconds to reconnect. This was solved by updating my NIC driver with a newer one from the vendor (Intel).</div>
<br />
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Usually you should be able to connect to the VMs from the host by connecting to eg. 192.168.137.2:3389. They won't have a ping though, so don't worry about that.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<b>Routing and Remote Access</b></div>
<div class="separator" style="clear: both; text-align: left;">
The same configuration can be acheived with RRAS on windows servers. This feature cannot be used together with ICS. Once you added this role in the server manager, open "mmc" and add the routing and remote access snap-in and add the local server.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
You can configure NAT by either selecting NAT directly in the wizard or by selecting custom configuration and just adding bare NAT, and then later adding interfaces yourself.</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgvXENdSwbHrRx5s2Xt0D1OE5lANyo19zBkFaCGbDKmbSG5m-4_VpmkgxJGdmBZ_L4MWsg0NyVTX8eRq-67U-g2PcntYElRzZf_pp-bChuZB4SHGwI89l3Nh5SAeOlMPET667PAOJe8Ez8/s1600/RRAS-NAT.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="326" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgvXENdSwbHrRx5s2Xt0D1OE5lANyo19zBkFaCGbDKmbSG5m-4_VpmkgxJGdmBZ_L4MWsg0NyVTX8eRq-67U-g2PcntYElRzZf_pp-bChuZB4SHGwI89l3Nh5SAeOlMPET667PAOJe8Ez8/s640/RRAS-NAT.png" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div>
To use NAT, you have to have two interfaces added:</div>
<div>
<ul style="text-align: left;">
<li>the external NIC added as "public interface connected to the internet"</li>
<li>the internal switch added as "private interface"</li>
</ul>
<div>
There are IPv4 settings if you right/click the local server. My setting is DHCP here, so no address pool is configured. In the NAT properties, Address Assignment tab:</div>
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj7T0WKz-HoNB0e-psPeKxg5CYXZXaz43I8-pA_FS3WIJUguj6sEwrV3lD-bjfEsRI4__4c83_80vZxhswJbPmDbV4PGsU2zukKP-udFLDJrJ2lm2JKaJe-CMMqt0rwHnHmU1Xr9K7mocU/s1600/RRAS-NAT-AddressAssignment.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj7T0WKz-HoNB0e-psPeKxg5CYXZXaz43I8-pA_FS3WIJUguj6sEwrV3lD-bjfEsRI4__4c83_80vZxhswJbPmDbV4PGsU2zukKP-udFLDJrJ2lm2JKaJe-CMMqt0rwHnHmU1Xr9K7mocU/s320/RRAS-NAT-AddressAssignment.png" width="286" /></a></div>
<div>
192.168.0.0/255.255.255.0 is configured. The wizard will configure this for you if you previously configure your Internal Switch:</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgRlrpCYwPUJIuQmgWz9ESXzU3ZLngxvsJEqXT_ML1Yxn9JFBjfQamb88teygAMeU_ZFXGSnjAhsYmBShOFNF1ubD1Ryv3pXFUVf3RPWPkU_8VmCUzMy_frOMujZs6thoafS__gz8ORlxI/s1600/RRAS-InternalSwitch-ipv4.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgRlrpCYwPUJIuQmgWz9ESXzU3ZLngxvsJEqXT_ML1Yxn9JFBjfQamb88teygAMeU_ZFXGSnjAhsYmBShOFNF1ubD1Ryv3pXFUVf3RPWPkU_8VmCUzMy_frOMujZs6thoafS__gz8ORlxI/s320/RRAS-InternalSwitch-ipv4.png" width="286" /></a></div>
<div>
<br /></div>
<div>
This produces the same stuff that ICS has. To add port forwarding you can go to the properties window of the public interface and click the services and ports tab. However, this has the same drawbacks as ICS port forwarding had: slow RDP sessions. They must have really messed up something there.</div>
<div>
<br /></div>
<div>
With this configuration you also should have access to VMs from the host machine directly, using their 192.168.0.x addresses.</div>
<div>
<br /></div>
<div>
I started to look for third-party port-forwarding tools, as it's quite an easy to implement stuff. <a href="http://codewut.de/Port-Redirection-with-Windows">Rinetd</a> worked fine, but it doesn't run as a windows service. After a bit of googling I found that windows itself can do portforwarding (of course): <a href="http://technet.microsoft.com/en-us/library/cc731068(v=ws.10).aspx">http://technet.microsoft.com/en-us/library/cc731068(v=ws.10).aspx</a> . So you can do this from an administrator command line:</div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">netsh interface portproxy add v4tov4 3397 192.168.0.2 3389</span></div>
<div>
<br /></div>
<div>
Use netsh interface portproxy to display additional options. With this configuration, port redirection works fine and RDP sessions work properly. This command also implicitly creates a firewall exception for the public port.</div>
<div>
<br /></div>
<div>
In case stuff stop working, reconfigure NAT from scratch. Also some rebooting will help.</div>
<h3 style="text-align: left;">
Summary</h3>
<div>
Having all this work properly took me painful weeks. Other forum posts also state that this functionality of the windows server is quite unstable. I feel lucky that I could finally come to a point where it works.</div>
<div>
<br /></div>
<div>
While this was not working I used VirtualBox and VMWare virtualization. They have this port-forwarding and NAT feature out-of-the-box and it just works with a few clicks. It's a shame that Hyper-V delegates this to ICS or RRAS, and finally you have to configure complicated stuff that don't finally work by default. Also, tutorials on technet just don't go into important details. They just say, 'enable NAT' and it will work. But it won't.</div>
<div>
<br /></div>
<div>
Also note that with vmware and virtualbox, if the host machine was connected to the company VPN, the virtual machines also accessed company intranet resources. With RRAS and ICS, VMs have to connect to VPN individually. Maybe there are routing settings that can solve this more easily, but after this torture, I wouldn't start configuring it.</div>
<div>
<br /></div>
<div>
I hope this helps other folks out there :)</div>
</div>
Gabor Farkashttp://www.blogger.com/profile/15102167846333868896noreply@blogger.com5tag:blogger.com,1999:blog-7787905651527345606.post-11771623768660347642012-05-15T16:57:00.000+02:002012-05-15T16:57:00.717+02:00JBoss AS 7 and PostgreSQL<div dir="ltr" style="text-align: left;" trbidi="on">
<div dir="ltr" style="text-align: left;" trbidi="on">
<div dir="ltr" style="text-align: left;" trbidi="on">
So, I'm having some fun migrating a major project to EE6. I've been playing around with Glassfish 3.1.2, but now I'm evaluating JBoss AS 7.1.1.<br />
<br />
First of all, I tried to use hibernate 4.1.1 bundled with my WAR file, but this caused this exception:<br />
<br />
<pre>Caused by: java.lang.ClassCastException: org.hibernate.ejb.connection.InjectedDataSourceConnectionProvider cannot be cast to org.hibernate.service.jdbc.connections.spi.ConnectionProvider
at org.hibernate.service.jdbc.connections.internal.ConnectionProviderInitiator.instantiateExplicitConnectionProvider(ConnectionProviderInitiator.java:187)
</pre>
<br />
I haven't yet found a way to resolve this, so for then I just went on using hibernate 4.0.1 in the AS. I guess it's mainly because the persistence unit in my application is loaded with the 4.1.1 jars, but the persistence unit, as it is deployed in the AS (not inside the WAR), is loaded by the 4.0.1 version. I'll give updates on this.<br />
<br />
So when staying with 4.0.1, everything deployed fine, but when performing an operation, I got this:</div>
<pre>Caused by: org.postgresql.util.PSQLException: Large Objects may not be used in auto-commit mode.
at org.postgresql.largeobject.LargeObjectManager.open(LargeObjectManager.java:200)
at org.postgresql.largeobject.LargeObjectManager.open(LargeObjectManager.java:172)
</pre>
</div>
<br />
Althought there's a hibernate.connection.autocommit setting that can be used in the persistence.xml, the problem was solved by enabling "Use JTA?" in the Datasource settings on the JBoss admin console.</div>Gabor Farkashttp://www.blogger.com/profile/15102167846333868896noreply@blogger.com0tag:blogger.com,1999:blog-7787905651527345606.post-5393179900268810472012-05-09T10:02:00.000+02:002012-05-09T10:11:29.784+02:00A JVM networking bug<div dir="ltr" style="text-align: left;" trbidi="on">
<span style="font-family: Arial, Helvetica, sans-serif;">My former colleagues sent me a strange error from a production jboss instance running on windows server 2003. Occasionally an AV terminates the VM:</span><br />
<span style="background-color: white; font-family: monospace; font-size: 13px;"><br /></span><br />
<span style="background-color: white; font-family: monospace; font-size: 13px;">EXCEPTION_ACCESS_VIOLATION (0xc0000005)</span>
<br />
<span style="background-color: white; font-family: monospace; font-size: 13px;"><br /></span><br />
<span style="background-color: white; font-family: monospace; font-size: 13px;">C [ntdll.dll+0x2b583] wcscpy+0x108</span><br />
<span style="background-color: white; font-family: monospace; font-size: 13px;">C [ntdll.dll+0x2ba81] RtlTimeFieldsToTime+0x2cb</span><br />
<span style="background-color: white; font-family: monospace; font-size: 13px;">C [ntdll.dll+0x2b646] wcscpy+0x1cb</span><br />
<span style="background-color: white; font-family: monospace; font-size: 13px;">C [msvcr71.dll+0x218a] free+0x39</span><br />
<span style="background-color: white; font-family: monospace; font-size: 13px;">C [net.dll+0x70fd] Java_java_net_SocketInputStream_socketRead0+0x1c6</span><br />
<span style="background-color: white; font-family: monospace; font-size: 13px;">J java.net.SocketInputStream.socketRead0(Ljava/io/FileDescriptor;[BIII)I</span>
<br />
<span style="background-color: white; font-family: monospace; font-size: 13px;"><br /></span><br />
<span style="font-family: Arial, Helvetica, sans-serif;">From another VM:</span><br />
<span style="background-color: white; font-family: monospace; font-size: 13px;"><br /></span><br />
<span style="background-color: white; font-family: monospace; font-size: 13px;">C [ntdll.dll+0x2be3e]</span><br />
<span style="background-color: white; font-family: monospace; font-size: 13px;">C [ntdll.dll+0x2b561]</span><br />
<span style="background-color: white; font-family: monospace; font-size: 13px;">C [ntdll.dll+0x2ba81]</span><br />
<span style="background-color: white; font-family: monospace; font-size: 13px;">C [ntdll.dll+0x2b646]</span><br />
<span style="background-color: white; font-family: monospace; font-size: 13px;">C [msvcr71.dll+0x218a]</span><br />
<span style="background-color: white; font-family: monospace; font-size: 13px;">C [net.dll+0x7129]</span><br />
<span style="background-color: white; font-family: monospace; font-size: 13px;">j java.net.SocketInputStream.socketRead0(Ljava/io/FileDescriptor;[BIII)I+0</span><br />
<span style="background-color: white; font-family: monospace; font-size: 13px;">j java.net.SocketInputStream.read([BII)I+84</span><br />
<span style="background-color: white; font-family: monospace; font-size: 13px;">j org.apache.coyote.http11.InternalInputBuffer.fill()Z+59</span>
<br />
<span style="background-color: white; font-family: monospace; font-size: 13px;"><br /></span><br />
<span style="font-family: Arial, Helvetica, sans-serif;">Checking some forums and stuff didn't help too much. There's even a bug for this <a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5040096">http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5040096</a> (I tried to comment on that bug, but this sun portal is not a friend of mine lately ... ) (also <a href="https://forums.oracle.com/forums/thread.jspa?threadID=1582665">https://forums.oracle.com/forums/thread.jspa?threadID=1582665</a> ).</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;">What I could figure out that the error must be in the JVM net.dll. It's quite strange though that the error seems to come only on "Windows Server 2003 family Build 3790 Service Pack 2".</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span><br />
<span style="font-family: Arial, Helvetica, sans-serif;">I checked the source of the socketRead0 method:</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"></span><br />
<pre class="cpp" name="code">/*
* Class: java_net_SocketInputStream
* Method: socketRead
* Signature: (Ljava/io/FileDescriptor;[BIII)I
*/
JNIEXPORT jint JNICALL
Java_java_net_SocketInputStream_socketRead0(JNIEnv *env, jobject this,
jobject fdObj, jbyteArray data,
jint off, jint len, jint timeout)
{
char *bufP;
char BUF[MAX_BUFFER_LEN];
jint fd, newfd;
jint nread;
if (IS_NULL(fdObj)) {
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "socket closed");
return -1;
}
fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
if (fd == -1) {
NET_ThrowSocketException(env, "Socket closed");
return -1;
}
/*
* If the caller buffer is large than our stack buffer then we allocate
* from the heap (up to a limit). If memory is exhausted we always use
* the stack buffer.
*/
if (len <= MAX_BUFFER_LEN) {
bufP = BUF;
} else {
if (len > MAX_HEAP_BUFFER_LEN) {
len = MAX_HEAP_BUFFER_LEN;
}
bufP = (char *)malloc((size_t)len);
if (bufP == NULL) {
/* allocation failed so use stack buffer */
bufP = BUF;
len = MAX_BUFFER_LEN;
}
}
if (timeout) {
if (timeout <= 5000 || !isRcvTimeoutSupported) {
int ret = NET_Timeout (fd, timeout);
if (ret <= 0) {
if (ret == 0) {
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
"Read timed out");
} else if (ret == JVM_IO_ERR) {
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "socket closed");
} else if (ret == JVM_IO_INTR) {
JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
"Operation interrupted");
}
if (bufP != BUF) {
free(bufP);
}
return -1;
}
/*check if the socket has been closed while we were in timeout*/
newfd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
if (newfd == -1) {
NET_ThrowSocketException(env, "Socket Closed");
return -1;
}
}
}
nread = recv(fd, bufP, len, 0);
if (nread > 0) {
(*env)->SetByteArrayRegion(env, data, off, nread, (jbyte *)bufP);
} else {
if (nread < 0) {
/*
* Recv failed.
*/
switch (WSAGetLastError()) {
case WSAEINTR:
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
"socket closed");
break;
case WSAECONNRESET:
case WSAESHUTDOWN:
/*
* Connection has been reset - Windows sometimes reports
* the reset as a shutdown error.
*/
JNU_ThrowByName(env, "sun/net/ConnectionResetException",
"");
break;
case WSAETIMEDOUT :
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
"Read timed out");
break;
default:
NET_ThrowCurrent(env, "recv failed");
}
}
}
if (bufP != BUF) {
free(bufP);
}
return nread;
}
</pre>
<br />
<span style="font-family: Arial, Helvetica, sans-serif;">And I found that on this line: "check if the socket has been closed while we were in timeout" - the method returns without releasing the possibly allocated bufP buffer. Well, I'm not good at C, but this seems to be a bug. And it's there in the latest jdk6 (31) as well, but it's fixed in OpenJdk7.</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;">So I think this is the error that somehow causes an AV on win2003. Upgrading to jdk7 should help.</span></div>Gabor Farkashttp://www.blogger.com/profile/15102167846333868896noreply@blogger.com0tag:blogger.com,1999:blog-7787905651527345606.post-11240382654381529982011-05-09T16:54:00.024+02:002011-05-18T10:37:57.791+02:00Testing a GWT/Mvp4g application in the JVM<p>
I develop a client for a logistics system in GWT, using <a href="http://code.google.com/p/mvp4g/" target="_blank">Mvp4g</a> (currently GWT 2.3 with Mvp4g 1.3.1). The system has technically quite complex integration tests, where a J5EE based (Glassfish 2.1 + Seam 2.2) core application serves multiple WPF clients (with web services using WCF and Metro) and multiple GWT web clients. I use the same infrastructure to test the overall performance of the system. It might not have been the best decision, but I didn't want to use Selenium at that time, and HtmlUnit had (maybe still has) some issues with my application which I didn't want to sort out (although it should work), so I chose to instantiate my GWT application in the JVM, using mock views. The main application code is in the presenters anyway, so it should be easy to use from a JVM. Well, not that easy, but not a catastrophe.
</p>
<h3>Presenters and the EventBus</h3>
<p>
So, presenters should be instantiable without modification in the JVM. Any GWT UI related code should be in the views, that's not a big restriction. The EventBus itself is generated at compile time by Mvp4g, and I didn't want to use those generators, probably the generated code runs only in a browser, due to the use of Guice, but maybe I'm wrong :).
</p>
<p>
Anyway, the EventBus is quite simple to implement with reflection and dynamic proxies. What we have to do is basically:
</p><ul>
<li>contain an instance of each presenter, and bind them to their views,</li>
<li>maintain a list of presenters handling each event</li>
<li>and delegate each event method invocation to those presenters, using the method name convetion.</li>
</ul>
So here is the code I use:
<p></p>
<pre name="code" class="java">import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Vector;
import com.google.inject.Injector;
import com.mvp4g.client.annotation.Event;
import com.mvp4g.client.annotation.InitHistory;
import com.mvp4g.client.event.EventHandlerInterface;
import com.mvp4g.client.presenter.PresenterInterface;
public class EventBus<T extends com.mvp4g.client.event.EventBus> {
Class<T> interfaceClass;
T eventBus;
@SuppressWarnings("unchecked")
Map<Class<PresenterInterface>, PresenterInterface> presenters = new HashMap<Class<PresenterInterface>, PresenterInterface>();
Map<String, EventDescriptor> events = new HashMap<String, EventDescriptor>();
EventDescriptor initEvent;
Injector injector;
@SuppressWarnings("unchecked")
public EventBus(Class<T> interfaceClass, Injector injector) {
this.injector = injector;
this.interfaceClass = interfaceClass;
eventBus = (T) Proxy.newProxyInstance(EventBus.class.getClassLoader(),
new Class [] { interfaceClass }, new EventBusInvocationHandler());
for (Method method : interfaceClass.getMethods())
if (method.isAnnotationPresent(Event.class)) {
Event event = method.getAnnotation(Event.class);
EventDescriptor eventDescriptor = new EventDescriptor();
eventDescriptor.method = method;
eventDescriptor.eventName = method.getName();
eventDescriptor.targetMethodName = "on" + Character.toUpperCase(eventDescriptor.eventName.charAt(0)) + eventDescriptor.eventName.substring(1);
for (Class<? extends EventHandlerInterface> cls : event.handlers())
eventDescriptor.handlers.add(getPresenter(cls));
events.put(eventDescriptor.eventName, eventDescriptor);
if (method.isAnnotationPresent(InitHistory.class))
initEvent = eventDescriptor;
}
}
@SuppressWarnings("unchecked")
public void bindView(Class<? extends PresenterInterface> presenterClass, Object view) {
PresenterInterface presenter = getPresenter(presenterClass);
presenter.setView(view);
presenter.setEventBus(eventBus);
presenter.bind();
}
public void init() {
try {
initEvent.method.invoke(eventBus);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
@SuppressWarnings("unchecked")
public <T extends EventHandlerInterface> T getPresenter(Class<T> presenterClass) {
T presenter = (T) presenters.get(presenterClass);
if (presenter == null) {
try {
presenter = injector.getInstance(presenterClass);
presenters.put((Class<PresenterInterface>) presenterClass, (PresenterInterface) presenter);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
return presenter;
}
public T getEventBus() {
return eventBus;
}
class EventDescriptor {
List<EventHandlerInterface> handlers = new Vector<EventHandlerInterface>();
String eventName;
String targetMethodName;
Method method;
}
class EventBusInvocationHandler implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if ("hashCode".equals(method.getName())) {
return EventBus.this.hashCode();
}
EventDescriptor eventDescriptor = events.get(method.getName());
for (EventHandlerInterface presenter : eventDescriptor.handlers) {
Method presenterMethod = presenter.getClass().getMethod(eventDescriptor.targetMethodName, eventDescriptor.method.getParameterTypes());
presenterMethod.invoke(presenter, args);
}
return null;
}
}
}
</pre>
<p></p>
<h3>The Application class</h3>
<p>
In Mvp4g you define the entry point (or use the mvp4g built in entry point) to bootstrap the framework. In JVM, we create an Application class that does the initialization.
While Mvp4g uses Gin, in the JVM we use Guice to do the injection stuff. There's nothing special to it, if you had a GinModule in Mvp4g, you can create a GuiceModule, and provide its injector to the EventBus above.
</p><p>
The Application contains and instantiates the GuiceModule, the EventBus and the mock views, and then calls EventBus#bindView method to give the views to the EventBus.
</p>
<p>
That's almost all, now you are able to instantiate your application, and play with it through the mock views. You might also directly call events from your test code.
</p>
<h3>GWT Service invocations</h3>
<p>
Well, if your application calls GWT services as well, you have to do some hacking about it. The GWT RPC implementation is not symmetric, which means that for example the Readers/Writers (Marshallers) are different on the client and server side. The stream written with a server side writer can only be read by a reader on the client side, not on the server side (classes: com.google.gwt.user.server.rpc.impl.(Client|Server)SerializaionStream(Writer|Reader) ).
</p>
<p>
Fortunately I wasn't the first to want to call a GWT RPC service from JVM, and there's a project called <a href="http://code.google.com/p/gwt-syncproxy/" target="_blank">gwt-syncproxy</a>. It can create sync and async proxies for you as well. I forked in my local workspace and added some functionality to support performance monitoring transparently (see below).
</p>
<p>
There was still a small issue. As I use this stuff from test code, I have to make sure that all async service invocations finish before I do my assertions in my tests. To achieve this, I extended gwt-syncproxy a little further, and added a little code that keeps track of invocations in each thread (and 'child'-threads), so that the test code can call a waitForInvocations() method before going on to the assertions.
</p>
<h3>I18n</h3>
<p>
When I added i18n to the application, my tests suddenly failed :) . It was because while in GWT, it creates and implementation of the message interface, in the JVM we have to replace it with something. Anyway, the localized strings are not so important during the tests, I don't call assertions textual content. However, there has to be an object with the interface. I love creating proxies, so here it is:
</p>
<pre name="code" class="java">import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import com.google.gwt.i18n.client.LocalizableResource.Key;
import com.google.gwt.i18n.client.Messages.DefaultMessage;
/**
* A class to implement com.google.gwt.i18n.client.Messages derived interfaces when running in a JVM
*/
public class MessagesFactory {
public static <T extends com.google.gwt.i18n.client.Messages> T createInstance(Class<T> cls) {
return (T) Proxy.newProxyInstance(MessagesFactory.class.getClassLoader(), new Class [] { cls },
new MessagesInvocationHandler(cls));
}
protected static class MessagesInvocationHandler<T extends com.google.gwt.i18n.client.Messages>
implements InvocationHandler {
protected Class<T> cls;
public MessagesInvocationHandler(Class<T> cls) {
this.cls = cls;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.isAnnotationPresent(DefaultMessage.class)) {
return method.getAnnotation(DefaultMessage.class).value();
}
if (method.isAnnotationPresent(Key.class)) {
return method.getAnnotation(Key.class).value();
}
return method.getName();
}
}
}
</pre>
<p>
And in the Guice module, I have to bind it manually:
</p>
<pre name="code" class="java">bind(MyMessages.class).toInstance(MessagesFactory.createInstance(MyMessages.class));
</pre>
<h3>Performance logging</h3>
<p>
Once I got the taste of using and extending everything in strage ways, I also added performance monitoring on the client side for GWT RPC invocations.
</p>
<p>
To proxy requests on the client side, I found a <a href="http://markmail.org/message/ci7c3ihl6yy2nuto#query:GWT%20dynamic%20proxy+page:1+mid:oqkp5nszcxoyosep+state:results" target="_blank">solution by Nathan Williams</a>. You can declare in your gwt.xml for which service interfaces you want to use the proxy and then use the bind method when creating the service to pass it an AsyncInvocationHandler that will be called before the actual invocation, and on success and failure. I also extended the gwt-syncproxy in my workspace to support these invocation handlers, and thus I can have my performance data from the integration and load tests too.
</p>Gabor Farkashttp://www.blogger.com/profile/15102167846333868896noreply@blogger.com0tag:blogger.com,1999:blog-7787905651527345606.post-15166094723934354232010-10-25T18:05:00.005+02:002010-10-25T18:19:58.803+02:00Seam, MDB, EJB and glassfish coming together<p>
The situation seems to be quite complex but I think it can happen to anyone :) So I have a Glassfish 2.1 appserver with Seam 2.2GA. I use several Seam components in the web tier and they interact with stateless EJBs as well, because some functionality has to be accessible through a remote EJB interface.
</p>
<p>
Injecting EJBs to Seam components are quite simple, just use the @In annotation. Seam will notice that it's a session bean, and use the default jndi name to look it up, as configured in the <code>components.xml</code>:
</p>
<pre>
<core:init jndi-pattern="java:comp/env/YOUR-APP-NAME/#{ejbName}/local"/>
</pre>
<p>
You can also inject Seam components to session beans, using the same @In annotation. Everything works fine, however, you have to define your local EJB references in the web.xml (on Glassfish), so that Seam can look them up from the web tier as well. Otherwise, local interfaces are not accessible from the web tier. The case is similar for Message Driven Beans (MDBs). Local interface references have to be declared.
</p>
<p>
If you just use @In annotations in your MDB (or any seam component invoked from the MDB), you'll get NameNotFoundExceptions for <code>"java:comp/env/YOUR-APP-NAME/YOUR-EJB-NAME/local"</code>.
</p>
<p>
You have to declare your ejb reference in your MDB, and the easiest way to do it is to use @EJB annotations in your MDB class. This would be fine, but by default, the JNDI name will be <code>"java:comp/env/your.message.driven.bean.full.ClassName/referenceVariableName"</code>, so you have to override it by using the <code>@EJB(name="YOUR-APP-NAME/YOUR-EJB-NAME/local"</code> annotation. By declaring this, Glassfish will make your local EJB interfaces accessible for the code running from the MDB.
</p>Gabor Farkashttp://www.blogger.com/profile/15102167846333868896noreply@blogger.com0tag:blogger.com,1999:blog-7787905651527345606.post-35457986728346997322010-10-01T11:22:00.008+02:002010-10-01T16:04:12.714+02:00Sun Glassfish and Oracle XE Distributed Transactions (XA)<p>
So, we're using Glassfish v2.1.1, currently with Oracle 10g XE, running on a Java 6 runtime, using ojdbc14.jar. And we wanted to use distributed transactions :) We are also using JBoss Seam 2.2, but that's unrelevant, fortunately.
</p>
<p>
We configured the connection pool to use <code>oracle.jdbc.xa.client.OracleXADataSource</code>, and we disabled 'Return non-transactional connections' of course. When we tried to access the database from our Seam-connected web tier, the following exceptions came up:
</p>
<pre>
[#|2010-10-01T12:09:12.383+0200|INFO|sun-appserver2.1|javax.enterprise.system.container.ejb|_ThreadID=22;_ThreadName=httpSSLWorkerThread-8091-1;|
javax.ejb.EJBException: nested exception is: javax.transaction.SystemException: org.omg.CORBA.INTERNAL: JTS5031: Exception [org.omg.CORBA.INTERNAL: vmcid: 0x0 minor code: 0 completed: Maybe] on Resource [rollback] operation. vmcid: 0x0 minor code: 0 completed: No
javax.transaction.SystemException: org.omg.CORBA.INTERNAL: JTS5031: Exception [org.omg.CORBA.INTERNAL: vmcid: 0x0 minor code: 0 completed: Maybe] on Resource [rollback] operation. vmcid: 0x0 minor code: 0 completed: No
at com.sun.jts.jta.TransactionManagerImpl.rollback(TransactionManagerImpl.java:350)
at com.sun.enterprise.distributedtx.J2EETransactionManagerImpl.rollback(J2EETransactionManagerImpl.java:1150)
at com.sun.enterprise.distributedtx.J2EETransactionManagerOpt.rollback(J2EETransactionManagerOpt.java:433)
at com.sun.ejb.containers.BaseContainer.completeNewTx(BaseContainer.java:3801)
at com.sun.ejb.containers.BaseContainer.postInvokeTx(BaseContainer.java:3619)
at com.sun.ejb.containers.BaseContainer.postInvoke(BaseContainer.java:1388)
at com.sun.ejb.containers.BaseContainer.postInvoke(BaseContainer.java:1325)
at com.sun.ejb.containers.EJBLocalObjectInvocationHandler.invoke(EJBLocalObjectInvocationHandler.java:205)
at com.sun.ejb.containers.EJBLocalObjectInvocationHandlerDelegate.invoke(EJBLocalObjectInvocationHandlerDelegate.java:127)
</pre>
<pre>
javax.ejb.EJBException: nested exception is: javax.transaction.SystemException: org.omg.CORBA.INTERNAL: JTS5031: Exception [org.omg.CORBA.INTERNAL: vmcid: 0x0 minor code: 0 completed: Maybe] on Resource [rollback] operation. vmcid: 0x0 minor code: 0 completed: No
at com.sun.ejb.containers.BaseContainer.postInvoke(BaseContainer.java:1395)
at com.sun.ejb.containers.BaseContainer.postInvoke(BaseContainer.java:1325)
at com.sun.ejb.containers.EJBLocalObjectInvocationHandler.invoke(EJBLocalObjectInvocationHandler.java:205)
at com.sun.ejb.containers.EJBLocalObjectInvocationHandlerDelegate.invoke(EJBLocalObjectInvocationHandlerDelegate.java:127)
</pre>
<pre>
[#|2010-10-01T14:20:10.992+0200|WARNING|sun-appserver2.1|javax.enterprise.system.core.transaction|_ThreadID=18;_ThreadName=httpSSLWorkerThread-8091-1;_RequestID=4131aa28-3401-4edd-bf90-54f605bcbb8e;|JTS5041: The resource manager is doing work outside a global transaction
oracle.jdbc.xa.OracleXAException
at oracle.jdbc.xa.OracleXAResource.checkError(OracleXAResource.java:1120)
at oracle.jdbc.xa.client.OracleXAResource.start(OracleXAResource.java:249)
at com.sun.gjc.spi.XAResourceImpl.start(XAResourceImpl.java:222)
at com.sun.jts.jta.TransactionState.startAssociation(TransactionState.java:305)
at com.sun.jts.jta.TransactionImpl.enlistResource(TransactionImpl.java:205)
at com.sun.enterprise.distributedtx.J2EETransaction.enlistResource(J2EETransaction.java:607)
at com.sun.enterprise.distributedtx.J2EETransactionManagerImpl.enlistResource(J2EETransactionManagerImpl.java:372)
at com.sun.enterprise.distributedtx.J2EETransactionManagerOpt.enlistResource(J2EETransactionManagerOpt.java:144)
at com.sun.enterprise.resource.SystemResourceManagerImpl.enlistResource(SystemResourceManagerImpl.java:98)
at com.sun.enterprise.resource.PoolManagerImpl.getResource(PoolManagerImpl.java:216)
at com.sun.enterprise.connectors.ConnectionManagerImpl.internalGetConnection(ConnectionManagerImpl.java:337)
at com.sun.enterprise.connectors.ConnectionManagerImpl.allocateConnection(ConnectionManagerImpl.java:189)
at com.sun.enterprise.connectors.ConnectionManagerImpl.allocateConnection(ConnectionManagerImpl.java:165)
at com.sun.enterprise.connectors.ConnectionManagerImpl.allocateConnection(ConnectionManagerImpl.java:158)
at com.sun.gjc.spi.base.DataSource.getConnection(DataSource.java:108)
at org.hibernate.connection.DatasourceConnectionProvider.getConnection(DatasourceConnectionProvider.java:92)
at org.hibernate.jdbc.ConnectionManager.openConnection(ConnectionManager.java:446)
at org.hibernate.jdbc.ConnectionManager.getConnection(ConnectionManager.java:167)
at org.hibernate.jdbc.AbstractBatcher.prepareSelectStatement(AbstractBatcher.java:145)
at org.hibernate.id.SequenceGenerator.generate(SequenceGenerator.java:96)
at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:122)
at org.hibernate.ejb.event.EJB3PersistEventListener.saveWithGeneratedId(EJB3PersistEventListener.java:49)
at org.hibernate.event.def.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:154)
at org.hibernate.event.def.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:110)
at org.hibernate.event.def.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:61)
at org.hibernate.impl.SessionImpl.firePersist(SessionImpl.java:646)
at org.hibernate.impl.SessionImpl.persist(SessionImpl.java:620)
at org.hibernate.impl.SessionImpl.persist(SessionImpl.java:624)
at org.hibernate.ejb.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:220)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.jboss.seam.persistence.EntityManagerInvocationHandler.invoke(EntityManagerInvocationHandler.java:46)
at $Proxy263.persist(Unknown Source)
</pre>
<p>
When switching to ojdbc5.jar or ojdbc6.jar, a further detail came in the logs. The exception above doesn't explain the cause of the OracleXAException (in OracleXAResource.start). This seems to be fixed in later drivers, so in the logs we can see:
</p>
<pre>
java.sql.SQLException: ORA-06550: line 1, column 13:
PLS-00201: identifier 'JAVA_XA.XA_START_NEW' must be declared
ORA-06550: line 1, column 7:
PL/SQL: Statement ignored
</pre>
<p>
Searching for this I got completely mislead. Forum entries say that there is no XA support in the XE version of 10g. Indeed, when I tried the whole stuff with Oracle 11g, it worked fine.
</p>
<p>
I wanted to try the stuff out myself to see how these XA handling looks like on the API level. I created a J2SE native app following the explanation and the code samples found here <a href="http://archive.devx.com/java/free/articles/dd_jta/jta-2.asp" target="_blank">http://archive.devx.com/java/free/articles/dd_jta/jta-2.asp</a> and here <a href="http://download.oracle.com/docs/cd/B14117_01/java.101/b10979/xadistra.htm" target="_blank">http://download.oracle.com/docs/cd/B14117_01/java.101/b10979/xadistra.htm</a>. And they worked fine, on Oracle 10g XE, with ojdbc14.jar. So obviously, <b>the 10g XE version does support XA.</b>
</p>
<p>
But why is it then that under Glassfish, it tries to use some fancy JAVA_XA package? It's my habit to jump into the source code of anything I can find, and even read the Eclipse class view showing the JVM level code. So I found that from my J2SE stuff, a T4CXAConnection is returned from the OracleXADataSource, but somewhy under glassfish, it is OracleXAConnection. So why is this difference? Browsing the binary of the OracleXADataSource class I found two suspicious properties named useNativeXA and thinUseNativeXA. And indeed, under glassfish, they were both false, despite their default values of useNativeXA=false, thinUseNativeXA=true.
</p>
<p>
Searching for these properties I found some explanations here <a href="http://download-west.oracle.com/docs/cd/B19306_01/java.102/b14355/xadistra.htm#BGBBHCFC" target="_blank">http://download-west.oracle.com/docs/cd/B19306_01/java.102/b14355/xadistra.htm#BGBBHCFC</a> and here <a href="http://openesb-users.794670.n2.nabble.com/Definition-of-Oracle-XA-datasources-td4461045.html" target="_blank">http://openesb-users.794670.n2.nabble.com/Definition-of-Oracle-XA-datasources-td4461045.html</a>. So, the Glassfish admin console proposes a default value of the useNativeXA=false, and setting this property also disables thinUseNativeXA. So we either remove this property, or set it to true (the additional properties page of the connnection pool properties), and it'll work fine.
</p>
<p>
So, after all, I should just have read "Oracle® Database JDBC Developer's Guide and Reference" to be aware of this feature in the jdbc driver :) . Hope it'll help you guys.
</p>Gabor Farkashttp://www.blogger.com/profile/15102167846333868896noreply@blogger.com3tag:blogger.com,1999:blog-7787905651527345606.post-42752410882455409762010-05-29T16:02:00.001+02:002010-05-29T13:01:30.904+02:00Logically deleted entities in Hibernate Search<p>
A recent project relies on Hibernate Search with a quite complex entity structure. We perform search on an entity that has several associated entities at multiple levels, and the search matches several text fields of the associated entities.
Everything worked quite fine, although with 3.1.1.GA we had to workaround this bug: <a href="http://opensource.atlassian.com/projects/hibernate/browse/HSEARCH-391" target="_blank">http://opensource.atlassian.com/projects/hibernate/browse/HSEARCH-391</a> (already fixed in 3.1.2).
</p><p>
The problem came when we started logically deleting associated entities (using a "deleted" boolean field), because the search still matched for text values of the deleted entities, and there seemed to be no proper way to exlude these indexes (and I think there is really not, as the indexes in lucene are 'flat').
Fortunately the hibernate community helped me out: <a href="https://forum.hibernate.org/viewtopic.php?f=9&t=1003745" target="_blank">https://forum.hibernate.org/viewtopic.php?f=9&t=1003745</a>
</p>
<p>
In my parent entities I filtered out these deleted entites from the collections, but this didn't make Hibernate Search drop the related indexes. The solution suggested in the forum was to actually remove the deleted entities from the owner collection, so actually breaking the relation between the entities. This might not be a solution in every case - you might need to keep the relation - but it helped me fortunately.
</p>Gabor Farkashttp://www.blogger.com/profile/15102167846333868896noreply@blogger.com0tag:blogger.com,1999:blog-7787905651527345606.post-53184103854450220732010-05-20T17:23:00.006+02:002010-05-20T17:41:40.853+02:00Using Vaadin with Seam<p>
I'm a big fan of both frameworks. Unfortunately, the direct ajax model doesn't yet integrate as well as JSF does with Seam. I created a model which does the trick, but I'm not that content with it yet (see <a href="http://hhc.intro.hu/daam/index.php?title=Main_Page" target="_blank">DAAM</a>), and the implementation is still experimental. For my current project I have to create some simple administration interfaces, for which Vaadin is a really neat choice. And of course I don't want to give up the convenience of Seam.
</p>
<p>
There's a simple way of enabling Seam stuff in a Vaadin application, as also proposed here: <a href="http://vaadin.com/forum/-/message_boards/message/116273" target="_blank">http://vaadin.com/forum/-/message_boards/message/116273</a>. This enables using Seam Contexts and Seam transaction management in your Vaadin application code. Somehow the solution didn't work out for me, so I created my own servlet filter which does the same two thing (contexts and transactions):
</p>
<pre name="code" class="java">
@Override
public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain) throws IOException, ServletException {
new ContextualHttpServletRequest((HttpServletRequest) request) {
@Override
public void process() throws Exception {
try {
beginTransaction();
chain.doFilter(request, response);
} finally {
commitOrRollBack();
}
}
}.run();
}
</pre>
<p>
The transaction handling methods are copy-pasted from the Seam JSF integration implementation:
</p>
<pre name="code" class="java">
/**
* Code from SeamPhaseListener (2.2.0 GA)
*/
public static void beginTransaction() {
try {
if (!Transaction.instance().isActiveOrMarkedRollback()) {
Transaction.instance().begin();
}
} catch (Exception e) {
throw new IllegalStateException("Could not start transaction", e);
}
}
/**
* Code from SeamPhaseListener (2.2.0 GA)
*/
public static void commitOrRollBack() {
try {
if (Transaction.instance().isActive()) {
try {
Transaction.instance().commit();
} catch (IllegalStateException e) {
log.info("TX commit failed with illegal state exception. This may be " + "because the tx timed out and was rolled back in the background.", e);
}
} else if (Transaction.instance().isRolledBackOrMarkedRollback()) {
Transaction.instance().rollback();
}
} catch (Exception e) {
throw new IllegalStateException("Could not commit transaction", e);
}
}
</pre>
<p>
But this is not all the way we can go. I want to use my EntityManager and other Seam components in my UI code. My UI classes are of course not Seam components (this is what is basically different in DAAM), but we can do a little trick. The methods in our UI classes are usually invoked by user interface events, eg. button clicks. I created a basic event delegate that, before actually invoking the delegated method, looks at the target object and handles its @In annotations. The implementation is quite simple:
</p>
<pre name="code" class="java">
public class InjectingEventDelegate {
Object component;
String methodName;
public InjectingEventDelegate(Object component, String methodName) {
this.component = component;
this.methodName = methodName;
}
public void doDelegate() {
inject();
try {
Method method = component.getClass().getMethod(methodName);
method.invoke(component);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
protected void inject() {
for (Field field : component.getClass().getDeclaredFields()) {
if (field.isAnnotationPresent(In.class)) {
In in = field.getAnnotation(In.class);
String name = field.getName();
if (!StringUtils.isEmpty(in.value()))
name = in.value();
Object toInject = Component.getInstance(name);
if (toInject == null)
throw new RuntimeException("Seam component with name '" + name + "' not found, trying to inject field " + field.getName() + " on " + component + " for invoking " + methodName);
try {
field.set(component, toInject);
} catch (Exception e) {
throw new RuntimeException("Count not inject field " + field.getName() + " on " + component + " for invoking " + methodName + ". Is the field declared public?", e);
}
}
}
}
}
</pre>
<p>
To help binding these delegates, I created an annotation based action binder, as follows
</p>
<pre name="code" class="java">
public class ActionBinder {
public static void bind(Object component) {
for (Field field : component.getClass().getDeclaredFields()) {
if (field.isAnnotationPresent(ActionBinding.class)) {
ActionBinding actionBinding = field.getAnnotation(ActionBinding.class);
try {
Object fieldValue = field.get(component);
Object delegate = new InjectingEventDelegate(component, actionBinding.value());
if (fieldValue instanceof Button) {
((Button)fieldValue).addListener(ClickEvent.class, delegate, "doDelegate");
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
}
}
</pre>
<p>
And that's it. We can now create UIs like this:
</p>
<pre name="code" class="java">
public class Page extends VerticalLayout {
@ActionBinding("add")
public Button addButton;
@In
public EntityManager em;
public Page() {
addButton = new Button("add");
addComponent(add);
ActionBinder.bind(this);
}
public void add() {
// do operations with EntityManager injected.
}
}
</pre>Gabor Farkashttp://www.blogger.com/profile/15102167846333868896noreply@blogger.com2tag:blogger.com,1999:blog-7787905651527345606.post-61880115769808121032010-05-19T13:57:00.000+02:002010-05-19T16:46:02.770+02:00<p>
Recently I had to port a solution consisting of several Seam applications from JBoss AS 4.2.2 to Glassfish v2.1. This had some tricky parts, mainly because Glassfish is strict about J2EE standard, while JBoss AS is quite not.
</p><p>
The exception which needed the most time to figure out was the one below:
</p>
<pre>
WARNING: JTS5054: Unexpected error occurred in after completion
java.lang.IllegalStateException: No event context active
at org.jboss.seam.ScopeType.getContext(ScopeType.java:121)
at org.jboss.seam.Component.getInstance(Component.java:1999)
at org.jboss.seam.Component.getInstance(Component.java:1994)
at org.jboss.seam.Component.getInstance(Component.java:1967)
at org.jboss.seam.Component.getInstance(Component.java:1962)
at org.jboss.seam.transaction.Transaction.instance(Transaction.java:39)
at org.jboss.seam.persistence.ManagedPersistenceContext.close(ManagedPersistenceContext.java:205)
at org.jboss.seam.persistence.ManagedPersistenceContext.afterCompletion(ManagedPersistenceContext.java:194)
at com.sun.jts.jta.SynchronizationImpl.after_completion(SynchronizationImpl.java:154)
at com.sun.jts.CosTransactions.RegisteredSyncs.distributeAfter(RegisteredSyncs.java:210)
at com.sun.jts.CosTransactions.TopCoordinator.afterCompletion(TopCoordinator.java:2585)
at com.sun.jts.CosTransactions.CoordinatorTerm.commit(CoordinatorTerm.java:433)
at com.sun.jts.CosTransactions.TerminatorImpl.commit(TerminatorImpl.java:250)
at com.sun.jts.CosTransactions.CurrentImpl.commit(CurrentImpl.java:623)
at com.sun.jts.jta.TransactionManagerImpl.commit(TransactionManagerImpl.java:309)
at com.sun.enterprise.distributedtx.J2EETransactionManagerImpl.commit(J2EETransactionManagerImpl.java:1029)
at com.sun.enterprise.distributedtx.J2EETransactionManagerOpt.commit(J2EETransactionManagerOpt.java:398)
at com.sun.enterprise.distributedtx.UserTransactionImpl.commit(UserTransactionImpl.java:197)
at org.jboss.seam.transaction.UTTransaction.commit(UTTransaction.java:52)
at *.SeamIntegrationFilter.commitOrRollBack(SeamIntegrationFilter.java:64)
at *.SeamIntegrationFilter$1.process(SeamIntegrationFilter.java:38)
at org.jboss.seam.servlet.ContextualHttpServletRequest.run(ContextualHttpServletRequest.java:53)
at *.SeamIntegrationFilter.doFilter(SeamIntegrationFilter.java:41)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:246)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:214)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:313)
at org.apache.catalina.core.StandardContextValve.invokeInternal(StandardContextValve.java:287)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:218)
at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:648)
at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:593)
at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:94)
at com.sun.enterprise.web.PESessionLockingStandardPipeline.invoke(PESessionLockingStandardPipeline.java:98)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:222)
at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:648)
at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:593)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:587)
at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:1096)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:166)
at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:648)
at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:593)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:587)
at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:1096)
at org.apache.coyote.tomcat5.CoyoteAdapter.service(CoyoteAdapter.java:288)
at com.sun.enterprise.web.connector.grizzly.DefaultProcessorTask.invokeAdapter(DefaultProcessorTask.java:647)
at com.sun.enterprise.web.connector.grizzly.DefaultProcessorTask.doProcess(DefaultProcessorTask.java:579)
at com.sun.enterprise.web.connector.grizzly.DefaultProcessorTask.process(DefaultProcessorTask.java:831)
at com.sun.enterprise.web.connector.grizzly.DefaultReadTask.executeProcessorTask(DefaultReadTask.java:341)
at com.sun.enterprise.web.connector.grizzly.DefaultReadTask.doTask(DefaultReadTask.java:263)
at com.sun.enterprise.web.connector.grizzly.DefaultReadTask.doTask(DefaultReadTask.java:214)
at com.sun.enterprise.web.portunif.PortUnificationPipeline$PUTask.doTask(PortUnificationPipeline.java:380)
at com.sun.enterprise.web.connector.grizzly.TaskBase.run(TaskBase.java:265)
at com.sun.enterprise.web.connector.grizzly.ssl.SSLWorkerThread.run(SSLWorkerThread.java:106)
</pre>
<p>
The above stack trace is of calling a remote EJB from a Seam integrated Vaadin application. However, a similar exception was thrown if I called the remote EJB method from a single (command line) client. The EJB method is marked as transactional (REQUIRED).
</p>
<p>
The issue seemed to be related to this: <a href="https://jira.jboss.org/browse/JBSEAM-3778" target="_blank">https://jira.jboss.org/browse/JBSEAM-3778</a> , althought I have no MDBs in the scenario. Upgrading to 2.2.1CR1 solved the problem.
</p>Gabor Farkashttp://www.blogger.com/profile/15102167846333868896noreply@blogger.com0tag:blogger.com,1999:blog-7787905651527345606.post-2146367636344316132010-02-15T18:06:00.001+01:002010-02-15T22:40:18.602+01:00An Ajax4JSF bug<p>The other day I had this exception:
</p>
<pre>
15:16:47,296 ERROR [[Faces Servlet]] Servlet.service() for servlet Faces Servlet threw exception
java.lang.NullPointerException
at org.ajax4jsf.org.w3c.tidy.Node.trimInitialSpace(Node.java:946)
at org.ajax4jsf.org.w3c.tidy.Node.trimSpaces(Node.java:1012)
at org.ajax4jsf.org.w3c.tidy.ParserImpl$ParseInline.parse(ParserImpl.java:1125)
at org.ajax4jsf.org.w3c.tidy.ParserImpl.parseTag(ParserImpl.java:203)
at org.ajax4jsf.org.w3c.tidy.ParserImpl$ParseRowGroup.parse(ParserImpl.java:2809)
at org.ajax4jsf.org.w3c.tidy.ParserImpl.parseTag(ParserImpl.java:203)
at org.ajax4jsf.org.w3c.tidy.ParserImpl$ParseTableTag.parse(ParserImpl.java:2629)
at org.ajax4jsf.org.w3c.tidy.ParserImpl.parseTag(ParserImpl.java:203)
at org.ajax4jsf.org.w3c.tidy.ParserImpl$ParseInline.parse(ParserImpl.java:1587)
at org.ajax4jsf.org.w3c.tidy.ParserImpl.parseTag(ParserImpl.java:203)
at org.ajax4jsf.org.w3c.tidy.ParserImpl$ParseBody.parse(ParserImpl.java:978)
at org.ajax4jsf.org.w3c.tidy.ParserImpl.parseTag(ParserImpl.java:203)
at org.ajax4jsf.org.w3c.tidy.ParserImpl$ParseHTML.parse(ParserImpl.java:486)
at org.ajax4jsf.org.w3c.tidy.ParserImpl.parseDocument(ParserImpl.java:3409)
at org.ajax4jsf.org.w3c.tidy.Tidy.parse(Tidy.java:363)
at org.ajax4jsf.org.w3c.tidy.Tidy.parse(Tidy.java:261)
at org.ajax4jsf.org.w3c.tidy.Tidy.parseDOM(Tidy.java:604)
at org.ajax4jsf.webapp.tidy.TidyParser.parseHtmlByTidy(TidyParser.java:182)
at org.ajax4jsf.webapp.tidy.TidyParser.parseHtml(TidyParser.java:265)
at org.ajax4jsf.webapp.FilterServletResponseWrapper.parseContent(FilterServletResponseWrapper.java:594)
at org.ajax4jsf.webapp.BaseXMLFilter.doXmlFilter(BaseXMLFilter.java:367)
at org.ajax4jsf.webapp.BaseFilter.handleRequest(BaseFilter.java:290)
at org.ajax4jsf.webapp.BaseFilter.processUploadsAndHandleRequest(BaseFilter.java:388)
at org.ajax4jsf.webapp.BaseFilter.doFilter(BaseFilter.java:515)
at org.jboss.seam.web.Ajax4jsfFilter.doFilter(Ajax4jsfFilter.java:56)
at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
at org.jboss.seam.web.LoggingFilter.doFilter(LoggingFilter.java:60)
at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
at org.jboss.seam.servlet.SeamFilter.doFilter(SeamFilter.java:158)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.jboss.web.tomcat.filters.ReplyHeaderFilter.doFilter(ReplyHeaderFilter.java:96)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:230)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
at org.jboss.web.tomcat.security.SecurityAssociationValve.invoke(SecurityAssociationValve.java:179)
at org.jboss.web.tomcat.security.JaccContextValve.invoke(JaccContextValve.java:84)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
at org.jboss.web.tomcat.service.jca.CachedConnectionValve.invoke(CachedConnectionValve.java:157)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:262)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:844)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583)
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:446)
at java.lang.Thread.run(Unknown Source)
</pre>
<p>I was using JSF 1.2_13-b01-FCS with RichFaces 3.3.2.SR1. The problem turned out to be with the generated HTML content which Ajax4JSF was sending as a response. We were using <code>a4j:repeat</code> to generate a HTML table, and one row of this table was shown using an AJAX request. However, the default rendering behaviour of a4j:outputPanel is the using of some element (span or div, I don't remember which is the actual default), and the html tidy code above had problems with handling those elements between table rows. You just have to define <code>layout="none"</code> for the outputPanel, then it works fine.</p>
<p>
The bug is since then reported: <a href="https://jira.jboss.org/jira/browse/AJSF-158" target="_blank">https://jira.jboss.org/jira/browse/AJSF-158</a>
</p>Gabor Farkashttp://www.blogger.com/profile/15102167846333868896noreply@blogger.com5tag:blogger.com,1999:blog-7787905651527345606.post-90451236354009009932010-02-09T16:30:00.000+01:002010-02-15T22:40:56.802+01:00Using action bindings in facelets template components<p>
When creating Facelets template components, you might face difficulties when trying to pass action bindings as component or template parameters. The problem is that the method binding gets evaluated at the place it is used, so if you write:
</p>
<pre>
<my:actionComponent action="#{backing.method}"/>
</pre>
<p>
the method is invoked and the result value will be available for named 'action' inside the template. To change this behaviour, I created a method in a backing named 'ELEvaluator':
</p>
<pre name="code" class="java">
public void evaluateMethodBinding(String el) {
ValueExpression ve = FacesContext.getCurrentInstance().getApplication().getExpressionFactory()
.createValueExpression(FacesContext.getCurrentInstance().getELContext(), "#{" + el + "}", Object.class);
ve.getValue(FacesContext.getCurrentInstance().getELContext());
}
</pre>
<p>
Inside the template component I use:
</p>
<pre>
action="#{ELEvaluator.evaluateMethodBinding(action)}"
</pre>
<p>
And when passing the action parameter, I have to pass a normal String, without the '#{}' stuff:
</p>
<pre>
<my:actionComponent [...] action="backing.method(params)"/>
</pre>
<p>
See also: <a href="http://seamframework.org/Community/FaceletsParamForActionMethod">http://seamframework.org/Community/FaceletsParamForActionMethod</a>
</p>Gabor Farkashttp://www.blogger.com/profile/15102167846333868896noreply@blogger.com0tag:blogger.com,1999:blog-7787905651527345606.post-8513093789399590662009-12-31T11:41:00.007+01:002009-12-31T16:19:43.890+01:00Having problems with WS-RM again<p>
I'm currently using Netbeans 6.7.1 with Glassfish v2.1. This Glassfish version is bundled with Metro 1.1.5. When trying to use WS-RM with these stuff, you can really easily run into problems.
</p><p>
If you set up a simple web project with a simple webservice, and enable Reliable Messaging (also enabling Delivering Messages In Exact Order), you get the stuff working right. You can see the added SOAP headers in the WS Tester page, and when monitoring Metro HTTP transfer (com.sun.xml.ws.transport.http.client.HttpTransportPipe.dump=true ), you can see that there are actually two request-response pairs.
</p><p>
But if you want to set up this simple scenario having EJBs included, it just won't work. Create a new EE project, add a stateless session bean with a dummy method, add a webservice on this bean, and enable RM and Order on it. I get the following exception in this case:
</p><pre>
java.lang.NullPointerException
at com.sun.ejb.containers.WebServiceInvocationHandler.invoke(WebServiceInvocationHandler.java:198)
at $Proxy96.greet(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at com.sun.enterprise.webservice.InvokerImpl.invoke(InvokerImpl.java:78)
at com.sun.enterprise.webservice.EjbInvokerImpl.invoke(EjbInvokerImpl.java:82)
at com.sun.xml.ws.server.InvokerTube$2.invoke(InvokerTube.java:146)
at com.sun.xml.ws.server.sei.EndpointMethodHandler.invoke(EndpointMethodHandler.java:257)
at com.sun.xml.ws.server.sei.SEIInvokerTube.processRequest(SEIInvokerTube.java:93)
at com.sun.xml.ws.api.pipe.Fiber.__doRun(Fiber.java:595)
at com.sun.xml.ws.api.pipe.Fiber._doRun(Fiber.java:554)
at com.sun.xml.ws.api.pipe.Fiber.doRun(Fiber.java:539)
at com.sun.xml.ws.api.pipe.Fiber.runSync(Fiber.java:436)
at com.sun.xml.ws.api.pipe.helper.AbstractTubeImpl.process(AbstractTubeImpl.java:106)
at com.sun.enterprise.webservice.MonitoringPipe.process(MonitoringPipe.java:147)
at com.sun.xml.ws.api.pipe.helper.PipeAdapter.processRequest(PipeAdapter.java:115)
at com.sun.xml.ws.api.pipe.Fiber.__doRun(Fiber.java:595)
at com.sun.xml.ws.api.pipe.Fiber._doRun(Fiber.java:554)
at com.sun.xml.ws.api.pipe.Fiber.doRun(Fiber.java:539)
at com.sun.xml.ws.api.pipe.Fiber.runSync(Fiber.java:436)
at com.sun.xml.ws.api.pipe.helper.AbstractTubeImpl.process(AbstractTubeImpl.java:106)
at com.sun.xml.ws.tx.service.TxServerPipe.process(TxServerPipe.java:317)
at com.sun.xml.ws.api.pipe.helper.PipeAdapter.processRequest(PipeAdapter.java:115)
at com.sun.xml.ws.api.pipe.Fiber.__doRun(Fiber.java:595)
at com.sun.xml.ws.api.pipe.Fiber._doRun(Fiber.java:554)
at com.sun.xml.ws.api.pipe.Fiber.doRun(Fiber.java:539)
at com.sun.xml.ws.api.pipe.Fiber.run(Fiber.java:388)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:619)
</pre>
<p>
In the current project, we yet have to stick to Metro version 1.1.5. Altought, I tried to set up the same configuration with Metro 1.5, and it worked fine.
</p><p>
But actually, you can get things working fine with Metro 1.1.5 as well. If you change the webservices libraries to the 1.5 implementation in Glassfish (as mentioned here: http://forums.netbeans.org/post-36125.html ), Netbeans will use .NET 3.5 / Metro 1.3 compatibility mode, and it will put WS-RM Policy 1.2 compliant stuff in the WSIT xml (xmlns:wsrm="http://docs.oasis-open.org/ws-rx/wsrmp/200702" ) However, with Metro 1.1.5, it uses .NET 3.0 / Metro 1.0 mode, it will tend to use WS-RM 1.1 (xmlns:wsrm="http://schemas.xmlsoap.org/ws/2005/02/rm/policy" ). But actually Metro 1.1.5 supports WS-RM 1.2 and WS Policy 1.5 (http://www.w3.org/ns/ws-policy ) - you can find it in the source code clearly.
</p>
<p>The problem seems to be not only with Metro 1.1.5 and WS-RM 1.1, but also with Metro 1.5 and WS-RM 1.1. In such situation, I get this exception:
</p><pre>
java.lang.NullPointerException
at com.sun.enterprise.webservice.SOAPMessageContextImpl.getMessage(SOAPMessageContextImpl.java:86)
at com.sun.enterprise.webservice.monitoring.MessageTraceImpl.setMessageContext(MessageTraceImpl.java:124)
at com.sun.enterprise.webservice.monitoring.JAXWSEndpointImpl.processResponse(JAXWSEndpointImpl.java:105)
at com.sun.enterprise.webservice.MonitoringPipe.process(MonitoringPipe.java:155)
at com.sun.xml.ws.api.pipe.helper.PipeAdapter.processRequest(PipeAdapter.java:115)
at com.sun.xml.ws.api.pipe.Fiber.__doRun(Fiber.java:598)
at com.sun.xml.ws.api.pipe.Fiber._doRun(Fiber.java:557)
at com.sun.xml.ws.api.pipe.Fiber.doRun(Fiber.java:542)
at com.sun.xml.ws.api.pipe.Fiber.runSync(Fiber.java:439)
at com.sun.xml.ws.api.pipe.helper.AbstractTubeImpl.process(AbstractTubeImpl.java:112)
at com.sun.xml.ws.tx.service.TxServerPipe.process(TxServerPipe.java:303)
at com.sun.xml.ws.api.pipe.helper.PipeAdapter.processRequest(PipeAdapter.java:115)
at com.sun.xml.ws.api.pipe.Fiber.__doRun(Fiber.java:598)
at com.sun.xml.ws.api.pipe.Fiber._doRun(Fiber.java:557)
at com.sun.xml.ws.api.pipe.Fiber.doRun(Fiber.java:542)
at com.sun.xml.ws.api.pipe.Fiber.runSync(Fiber.java:439)
at com.sun.xml.ws.api.pipe.helper.AbstractTubeImpl.process(AbstractTubeImpl.java:112)
at com.sun.enterprise.webservice.CommonServerSecurityPipe.processRequest(CommonServerSecurityPipe.java:222)
at com.sun.enterprise.webservice.CommonServerSecurityPipe.process(CommonServerSecurityPipe.java:133)
at com.sun.xml.ws.api.pipe.helper.PipeAdapter.processRequest(PipeAdapter.java:115)
at com.sun.xml.ws.api.pipe.Fiber.__doRun(Fiber.java:598)
at com.sun.xml.ws.api.pipe.Fiber._doRun(Fiber.java:557)
at com.sun.xml.ws.api.pipe.Fiber.doRun(Fiber.java:542)
at com.sun.xml.ws.api.pipe.Fiber.runSync(Fiber.java:439)
at com.sun.xml.ws.server.WSEndpointImpl$2.process(WSEndpointImpl.java:243)
at com.sun.xml.ws.transport.http.HttpAdapter$HttpToolkit.handle(HttpAdapter.java:471)
at com.sun.xml.ws.transport.http.HttpAdapter.handle(HttpAdapter.java:244)
at com.sun.xml.ws.transport.http.servlet.ServletAdapter.handle(ServletAdapter.java:135)
at com.sun.enterprise.webservice.Ejb3MessageDispatcher.handlePost(Ejb3MessageDispatcher.java:113)
at com.sun.enterprise.webservice.Ejb3MessageDispatcher.invoke(Ejb3MessageDispatcher.java:87)
at com.sun.enterprise.webservice.EjbWebServiceServlet.dispatchToEjbEndpoint(EjbWebServiceServlet.java:228)
at com.sun.enterprise.webservice.EjbWebServiceServlet.service(EjbWebServiceServlet.java:157)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:847)
at com.sun.enterprise.web.AdHocContextValve.invoke(AdHocContextValve.java:114)
at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:648)
at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:593)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:587)
at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:87)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:222)
at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:648)
at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:593)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:587)
at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:1096)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:166)
at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:648)
at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:593)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:587)
at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:1096)
at org.apache.coyote.tomcat5.CoyoteAdapter.service(CoyoteAdapter.java:288)
at com.sun.enterprise.web.connector.grizzly.DefaultProcessorTask.invokeAdapter(DefaultProcessorTask.java:647)
at com.sun.enterprise.web.connector.grizzly.DefaultProcessorTask.doProcess(DefaultProcessorTask.java:579)
at com.sun.enterprise.web.connector.grizzly.DefaultProcessorTask.process(DefaultProcessorTask.java:831)
at com.sun.enterprise.web.connector.grizzly.DefaultReadTask.executeProcessorTask(DefaultReadTask.java:341)
at com.sun.enterprise.web.connector.grizzly.DefaultReadTask.doTask(DefaultReadTask.java:263)
at com.sun.enterprise.web.connector.grizzly.DefaultReadTask.doTask(DefaultReadTask.java:214)
at com.sun.enterprise.web.portunif.PortUnificationPipeline$PUTask.doTask(PortUnificationPipeline.java:380)
at com.sun.enterprise.web.connector.grizzly.TaskBase.run(TaskBase.java:265)
at com.sun.enterprise.web.connector.grizzly.ssl.SSLWorkerThread.run(SSLWorkerThread.java:106)
</pre><p>
Such exception can be found in two reported bugs: https://glassfish.dev.java.net/issues/show_bug.cgi?id=7981 , and http://netbeans.org/bugzilla/show_bug.cgi?id=163210
</p><p>
Quite a mess. So - if you can switch to a newer Metro implementation, do it. Otherwise, just change the declarations in your wsit-*.xml (replace those generated by netbeans) to the WS-RM 1.2 and WSP 1.5 ones, and it should work fine.
</p>Gabor Farkashttp://www.blogger.com/profile/15102167846333868896noreply@blogger.com0tag:blogger.com,1999:blog-7787905651527345606.post-3112012128467056712009-11-25T17:20:00.007+01:002009-12-15T21:19:31.304+01:00Metro WS-AT transaction coordination and https<p>
I recently had to configure a secure and reliable webservice connection. We use WS-AtomicTransactions, WS-Security (Mutual Certificates Security, MCS) and WS-ReliableMessaging, however all this over HTTP transport (not HTTPS).
Things are quite easy to set up with Netbeans (6.7.1) and Glassfish v2.1 (which uses Metro 1.1.5). But at some point it is just not working, and you have no more buttons to click in the wizard windows.
</p><p>
The situation was simple, I used two different projects to pilot the solution. Both had a simple EJB Session bean with a method, also published as webservice operation. From one of the EJBs I invoked the other with WS (this connection had AT, RM and Security configured). I tested the first WS with its standard Tester. The two applications got deployed on two different glassfish domains, just to make sure.
</p><p>
The problem came when I enabled transactions:
<pre>
WSTX-COORDINATOR-3006: register sent to EPR '<?xml version="1.0" encoding="UTF-8"
standalone="yes"?><EndpointReference xmlns="http://schemas.xmlsoap.org/ws/2004
/08/addressing"><Address>https://hhcofcmds:8281/__wstx-services/wscoor/coordinator
/register</Address><ReferenceParameters><jaxws:objectId
xmlns:ns2="http://schemas.xmlsoap.org/ws/2004/08/addressing"
xmlns="http://schemas.xmlsoap.org/ws/2004/10/wscoor" xmlns:jaxws="http://jax-
ws.dev.java.net/xml/ns/" xmlns:wsa="http://schemas.xmlsoap.org/ws/2004
/08/addressing" xmlns:ns3="http://schemas.xmlsoap.org/soap/envelope/">7ef29c5a-
2633-40a7-ae4a-54d94e818ec0</jaxws:objectId></ReferenceParameters>
</EndpointReference>' failed for activityId 'uuid:WSCOOR-SUN-3871ef38-e5b2-490c-
9fbe-a39fa442daee'. Nested exception: 'HTTP transport error:
javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX
path building failed: sun.security.provider.certpath.SunCertPathBuilderException:
unable to find valid certification path to requested target'
WSTX-AT-0022: Registration with durable parent failed: ' coordId=uuid:WSCOOR-
SUN-3871ef38-e5b2-490c-9fbe-a39fa442daee partId:1 '
</pre>
<p>
Some forum entries suggest that I should disable transactions on the invoked WS. Well, this is not an option for me, as having transactions was my actual intent. So, WS-AT and WS-RM use some additional WS invocations to the transaction coordinator service to ensure all the stuff it has to ensure. The logs above show that someone tries to contact the coordinator over https. Which surely won't be wokring, as I use http transfer for the whole stuff.
</p><p>
I found a note in some forum post that the coordination stuff uses https by default. So I dived into the source to find this in class <code>com.sun.xml.ws.tx.common.AddressManager</code>
</p>
<pre class="ae-logs-expanded ae-pre-wrap">
private static String preferredScheme =
System.getProperty("com.sun.xml.ws.tx.preferredScheme", "https");
</pre>
<p>
The methods getPreferredAddress and getAddress use this setting. So we just have to add this line in the proper place in the domain.xml of both glassfish domains:
</p>
<pre class="ae-logs-expanded ae-pre-wrap">
<jvm-options>-Dcom.sun.xml.ws.tx.preferredScheme=http</jvm-options>
</pre>
<p>
This will cause the transaction coordination to use http transfer.
</p>Gabor Farkashttp://www.blogger.com/profile/15102167846333868896noreply@blogger.com1tag:blogger.com,1999:blog-7787905651527345606.post-9818960684315196492009-10-14T13:33:00.005+02:002009-10-16T22:51:36.447+02:00A tricky thing about generics<p>
I ran into this a couple of times now. When using numbers as keys in maps, you have to be really careful with number literals. Number literals by default compile to be of <code>int</code> primitive type and they can be automatically cast (boxed) to Object as Integers.
</p>
<p>
Take the code below:
</p>
<pre name="code" class="java">
public class Test {
static Map<Long, String> testMap = new HashMap<Long, String>();
public static void main(String[] args) {
testMap.put((long)0, "zero");
System.out.println(testMap.get((long)0));
System.out.println(testMap.get(0));
}
}
</pre>
<p>
Notice the cast to <code>long</code> primitive type, <code>tesMap.put(0, "zero")</code> won't even compile. The unfortunate thing is only that the <code>java.util.Map.get</code> method is not parametrized with the Key class of the Map, so <code>testMap.get(0)</code> compiles without errors, but it returns null.
</p>Gabor Farkashttp://www.blogger.com/profile/15102167846333868896noreply@blogger.com0tag:blogger.com,1999:blog-7787905651527345606.post-17780638268313394352009-05-22T11:05:00.000+02:002009-05-24T12:02:12.891+02:00Using GWT and Ajax4jsf together<p>Recently I had to face a situation it's hard to speak about :) In a Seam+RichFaces based application we needed to develop a special component, which needs a large amount of client side JavaScript code. I decided to use GWT to develop this functionality. It's very simple to embed a GWT application supporting a JSF component to a page, especially if you have only one instance of the component on the page - you just include the compiled JS.
</p><p>
Everything seemed working fine until I tested it in Internet Explorer 6. In IE6, the GWT RPC calls just didn't succeed, the IE6 JavaScript error report said 'unhandled exception', in a meaningless line of JS code, of course. I found that it works fine if I don't have an a4j:form on my page. After a number of tries I found that the loading of the core JavaScript library of Ajax4Jsf already causes the problem, and then, looking through the code, I found a suspicious statement:
</p>
<pre name="code" class="java">
XMLHttpRequest = function() {
if (!_SARISSA_XMLHTTP_PROGID) {
_SARISSA_XMLHTTP_PROGID = Sarissa.pickRecentProgID( [
"Msxml2.XMLHTTP.6.0", "MSXML2.XMLHTTP.3.0",
"MSXML2.XMLHTTP", "Microsoft.XMLHTTP" ]);
}
return new ActiveXObject(_SARISSA_XMLHTTP_PROGID);
};
</pre>
<p>
And this turned out to be the problem indeed. Normally, the XMLHttpRequest variable is simply null. I didn't dare look through the GWT RPC implementation to investigate the problem further :) But at this point, we can already work the thing around.
</p><p>
So I introduced a 'beforeRequest' and 'afterRequest' JSNI methods in my GWT code to ensure that '$wnd.XMLHttpRequest' is null during the RPC call. This way, GWT RPC calls work fine, and the normal a4j functionality is still available in the page.
</p>Gabor Farkashttp://www.blogger.com/profile/15102167846333868896noreply@blogger.com0tag:blogger.com,1999:blog-7787905651527345606.post-60055300782382201782009-05-12T21:11:00.001+02:002009-05-24T12:06:57.626+02:00Showing not shown Faces Messages<p>Most of us using JSF 1.2 RI are familiar with the warning message in our logs:</p>
<pre class="wikiPreformatted">[lifecycle] WARNING: FacesMessage(s) have been enqueued, but may not have been displayed.
</pre>
<p>JavaServer Faces has a mechanism to assign messages to specific components. In the common case, if an input field has a validation error, the error message is queued to that field, and a h:message put next to the input field can show the message on the page:</p>
<pre name="code" class="xml">
<h:inputtext id="firstName"/>
<h:message for="firstName"/>
</pre>
<p>
The JSF Reference Implementation has a solution to help us find out if we forgot to put a h:message tag for some components. Unfortunately, it only shows a warning message in the log, and we have no programmatic way to process those messages. Well, almost no way.
</p><p>
If you dare take a look in com.sun.faces.lifecycle.RenderResponsePhase, you can see that if there are any messages queued, a special variable of the Set is added to the request map. All client ids of controls with faces messages are added to this set. When h:message tags render, they access the messages queued for their associated client ids using the getMessages(String clientId) method in com.sun.faces.context.FacesContextImpl. This method removes the client id from the set, thus signalling that the messages for that client id are displayed. When finished rendering, messages for the client ids remaining in the Set are those that are not displayed. The class RenderResponsePhase simply logs these messages and then disposes the Set.
</p><p>
In one of my applications, I wanted to present these messages at the top of my forms. This can come really useful especially in development phase. As seen from the above, I have the necessary information ready at the very end of each render phase. I created a Seam component with a method to handle it:
</p>
<pre name="code" class="java">
@Name("messageHandler")
public class MessageHandler {
public String handleUnAssignedMessages() {
// copy-paste from com.sun.faces.lifecycle.RenderResponsePhase
Set<string> clientIds = TypedCollections.dynamicallyCastSet(
(Set) FacesContext.getCurrentInstance().getExternalContext().getRequestMap()
.remove(RIConstants.CLIENT_ID_MESSAGES_NOT_DISPLAYED), String.class);
if (clientIds != null)
for (String clientId : clientIds) {
Iterator<facesmessage> messages =
FacesContext.getCurrentInstance().getMessages(clientId);
while (messages.hasNext()) {
FacesMessage message = messages.next();
if (message.getSeverity() == FacesMessage.SEVERITY_ERROR ||
message.getSeverity() == FacesMessage.SEVERITY_FATAL) {
String text = message.getSummary() + " " + message.getDetail();
FacesContext.getCurrentInstance().addMessage(null,
new FacesMessage(FacesMessage.SEVERITY_ERROR, text, text));
}
}
}
return "";
}
}
</pre>
<p>
This method simply collects all nondisplayed error messages and enqueues them without assigning them to a specific client id. Note that you'll have to include the jsf-impl.jar in your classpath for this code to compile. Having these messages enqueued, you can present them by a h:messages tag, or you can do anything programmatically with them.
</p><p>
Note that as you only have this information at the end of the render phase, you have to put the invocation of this method at the end of your page. If you want also to present them on the page with a h:messages tag, you have to put it after the invocation of the method above. You can then move the html output to the desired place in your document (above your forms, probably) with a simple javascript code:
</p>
<pre name="code" class="xml">
<div id="messages-holder"></div>
<form></form>
<div id="messages-holder-source">
#{messageHandler.handleUnAssignedMessages()}
<h:messages layout="table" styleclass="msg_gl"
infoclass="info-message"
warnclass="warning-message"
errorclass="error-message"
globalonly="#{true}"
showsummary="#{false}"
showdetail="#{true}">
</h:messages>
</div>
<script>
document.getElementById('messages-holder').innerHTML =
document.getElementById('messages-holder-source').innerHTML;
document.getElementById('messages-holder-source').innerHTML = "";
</script>
</pre>
<p>
So that's it.
<p>Gabor Farkashttp://www.blogger.com/profile/15102167846333868896noreply@blogger.com0tag:blogger.com,1999:blog-7787905651527345606.post-89209635423155004472009-04-28T21:03:00.000+02:002009-05-12T22:01:03.630+02:00Experiences with AppEngine<p>Well, I was quite excited to get my Java early look request accepted. I'm publishing an application soon (I'll write about it later). After the initial success with the "hello world" application I soon had to face some problems.</p>
<p>
At my first test project, I started to work with JPA. The list of unsupported features in the <a href="http://code.google.com/appengine/docs/java/datastore/usingjpa.html">docs</a> didn't scare me much. But then found more. First of all, for Id generation, only Identity generation type is supported, but that's a minor issue. A bigger problem was that I could not persist multiple entities in one EntityManager session. This might have been solved by some configuration on Datanucleus, with which I am not familiar, and which I did not start to search for. Finally I just did not manage to persist an associated entity. I got exceptions stating that the parent entity is already persisted with another Id, however the parent entity class mentioned by the exception was actually the child entity. Anyone more familiar with Datanucleus can surely get further.
</p><p>
Then I started to use the JDO framework. I soon ran into the exception mentioned also <a href="http://groups.google.hu/group/google-appengine-java/browse_thread/thread/ba7f6868ffbebbc9/658b98e0976fe2a?hl=en&ie=UTF-8">here</a>, but as there said, it just got resolved at some point, I don't know why.
</p><p>
I had the most problems with my web framework. I'm using an own experimental Direct Ajax framework, called <a href="http://daam.wiki.sourceforge.net/">Daam</a>, which is originally designed to work integrated with JBoss Seam, but with some modifications it could be used in the AppEngine environment. A serious thing to consider was that I really have to store all my application information manually in the http session context, and I guess I cannot assume that the same servlet instance will handle all requests of a session. These things are handled by JBoss Seam in the original architecture.
</p><p>
The problems came when I deployed in online. First of all, java.lang.reflect.Method is not serializable, but the deserialization of some objects can be unsuccessful. The exception is similar to the one mentioned in the issue <a href="http://code.google.com/p/googleappengine/issues/detail?id=1290">1290</a>, but I had it with any Object [] or String [] arrays.
</p>
<pre class="ae-logs-expanded ae-pre-wrap">Nested in javax.servlet.ServletException: [Ljava.lang.String;:
java.lang.ArrayStoreException: [Ljava.lang.String;
at java.io.ObjectInputStream.readArray(Unknown Source)
[...]
at com.google.apphosting.runtime.jetty.SessionManager.deserialize(SessionManager.java:358)
</pre>
<p>It also seems that SimpleDateFormat also contains arrays. I had to turn my array fields into Lists and I had to declare my DateFormat fields transient and reinitiate them on need. Later I also found <a href="http://groups.google.hu/group/google-appengine-java/browse_thread/thread/a7ea6dd1e097d496/dfa9ee4c4414d0af?hl=en&ie=UTF-8&oe=utf-8">this post</a>.
That's it for now, I hope it will help some.
</p>Gabor Farkashttp://www.blogger.com/profile/15102167846333868896noreply@blogger.com0