Sunday, December 20, 2009

I am Sun Certified Business Component Developer!

I am very happy to announce that I passed Sun Certified Business Component Developer for the Java Platform, Enterprise Edition 5 (CX-310-091) exam with an astounding score of 100%!

The exam turned out to be easier than I expected (that is somewhat reflected by my score :D). I was also surprised by the fact that there were no drag-and-drop questions — the exam page mentions about them. Maybe the questions are randomized without taking the type into account or I simply did it so automatically that I didn't even noticed.

While preparing to the exam, I answered a fair amount of questions from JavaBlackBelt EJB section and the ones provided as a demo by various exam simulators, and I got the impression that the exam will test my knowledge of both specifications rather thoroughly. I've expected questions regarding e.g. declarative security in conjunction with both inheritance and XML descriptors or some twisted JPQL queries. That wasn't the case. Actually, of 61 questions about six were somewhat tricky and involved really good understanding of the subtleties. There were also 4 or 5 that were IMHO ambiguously formulated, provided additional, unnecessary details in the statements or were so obvious and unclear at the same moment that I sit there ruminating where is the catch. The majority of the questions, which is far than sufficient to pass the exam, were written really good and tested in scenario-based fashion the knowledge that I find absolutely compulsory for the developer to have.

It goes like this: think you know what each transaction attribute does? Show you understand the reason behind their creation, by choosing the most appropriate one for a given real-world scenario. This is what you are doing on the job and also my way of learning. I find it a real leap in the terms of exam quality, comparing to Sun Certified Java Programmer one. I'm not saying I know the way to construct a better exam for this level, but the problems from SCJP seemed very artificial to me. I felt like reading code of a guy that should be sentenced for writing it that way, while being in some sort of captivity myself, because I haven't got even a compiler, not to mention some code editor with syntax highlighting. That's a nightmare, not an exam.

I heard that new SCJP exam (called SCJP+ as far as I remember) is designed as a set of short programming tasks involving writing a real code. This problem-solving approach is in my opinion the best way to build the exams if we want Sun's certification to be highly valued in the market.

My certification is already outdated as the Java EE 6 came out last week :). Put the (probable) two years adoption period aside, there is something to worry about — as depicted on this page, the future SCBCD exam is to be split into EJB and JPA specific ones. While I find this move very rational, I am afraid that it will mean that the certification fee will double. I wish I were wrong.

To sum up, I feel that I've learnt pretty much about Java EE 5 through my preparation for the exam and feel really satisfied, since that was the point of this whole effort. I'm now pretty confident of the platform's strong and weak points. The broader knowledge of the shortcomings make me lean (language joke, yeah) toward Spring 3.0, as Java EE 6 doesn't seem to resolve them. I'll write more as soon as I'll get a good grasp of both.

Monday, November 30, 2009

Preparing for the Sun Certified Business Component Developer Exam

I did not have time to write recently, because I am busy preparing for the Sun Certified Business Component Developer exam. I am taking it in a little over two weeks, so this period of my blogging inactivity hopefully won't last long.

I chose the "EJB 3 in Action" as my main textbook and read EJB Core and Persistence specifications thoroughly. The last two are important to me as they operate with the language I expect to encounter at the exam. I find it not so uncommon for big vendors to use their sole own bits of terminology (for example in the web services realm).

I am also using Sun Java EE Tutorial as a refresher and contributing to JavaBlackBelt EJB 3 exams. I also find it convenient to choose NetBeans and Glassfish v2 as my playground to test some boundary cases I conceive. Generally, I am an Eclipse guy and many things in NetBeans (especially its editor) are counter-intuitive to me, but its "Verify" option is very helpful in the preparation. It basically checks whether the EJB project fulfills specification restrictions (in fact, some proper subset of them). Using reference application server saves me from checking every little doubt in the documentation, since I admit to believe in such empirical knowledge gathering. Nevertheless, I've already found some things that should be signaled by an exception, but were graciously unsaid by the server.

All in all, I've enjoyed the preparation to this exam a way better than to the SCJP one so far and hope to say the same after taking it.

Saturday, September 5, 2009

Configuring an encrypted connection between WAS 6.1 and Oracle 10g with server authentication

I stumbled upon some obstacles while configuring a secured connection between WebSphere Application Server 6.1.0.17 and Oracle 10g Release 2 over TCPS. The requirement was to establish an encrypted connection with server (i.e. database listener) authentication. It is realized in the second scenario described in Oracle's guide for enabling SSL on JDBC thin driver. It seems all pretty straightforward and in fact it is — on the Sun's JVM the following code works like a charm (tested with ojdbc14.jar for Oracle 10g Release 2):

import java.util.Properties;
import java.sql.*;

class OracleSSLTest {
  public static void main(String[] args) throws Exception {
    DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver());
    String url = "jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS=(PROTOCOL=tcps)(HOST=oracle)(PORT=2484)) (CONNECT_DATA=(SERVICE_NAME=TESTSSL)(SERVER=DEDICATED)))";
    Properties props = new Properties();
    props.setProperty("user", "testssl");
    props.setProperty("password", "testssl");
    props.setProperty("javax.net.ssl.trustStore", "client.jks");
    props.setProperty("javax.net.ssl.trustStoreType", "JKS");
    props.setProperty("javax.net.ssl.trustStorePassword", "password");

    Connection conn = DriverManager.getConnection(url, props);
    System.out.println("Great success!");
  }
}

However, the same code launched on IBM JVM (build 2.3, J2RE 1.5.0 IBM J9 2.3 Linux amd64-64 j9vmxa6423-20080315) generates the following exception:

Exception in thread "main" java.sql.SQLException: I/O Exception: The Network Adapter could not establish the connection
  at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:112)
  at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:146)
  at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:255)
  at oracle.jdbc.driver.T4CConnection.logon(T4CConnection.java:387)
  at oracle.jdbc.driver.PhysicalConnection.<init>(PhysicalConnection.java:441)
  at oracle.jdbc.driver.T4CConnection.<init>(T4CConnection.java:165)
  at oracle.jdbc.driver.T4CDriverExtension.getConnection(T4CDriverExtension.java:35)
  at oracle.jdbc.driver.OracleDriver.connect(OracleDriver.java:801)
  at java.sql.DriverManager.getConnection(DriverManager.java:562)
  at java.sql.DriverManager.getConnection(DriverManager.java:155)
  at OracleSSLTest.main(Test.java:15)

I've checked that GIJ behaves similar. Running the code with a newer JDBC driver, namely ojdbc5.jar, gives more descriptive messages (the improved verbosity of the new drivers can save you a lot of time):

Exception in thread "main" java.sql.SQLException: The Network Adapter could not establish the connection
  at oracle.jdbc.driver.T4CConnection.logon(T4CConnection.java:412)
  at oracle.jdbc.driver.PhysicalConnection.<init>(PhysicalConnection.java:531)
  at oracle.jdbc.driver.T4CConnection.<init>(T4CConnection.java:221)
  at oracle.jdbc.driver.T4CDriverExtension.getConnection(T4CDriverExtension.java:32)
  at oracle.jdbc.driver.OracleDriver.connect(OracleDriver.java:503)
  at java.sql.DriverManager.getConnection(DriverManager.java:562)
  at java.sql.DriverManager.getConnection(DriverManager.java:155)
  at OracleSSLTest.main(Test.java:15)
Caused by: oracle.net.ns.NetException: The Network Adapter could not establish the connection
  at oracle.net.nt.ConnStrategy.execute(ConnStrategy.java:359)
  at oracle.net.resolver.AddrResolution.resolveAndExecute(AddrResolution.java:422)
  at oracle.net.ns.NSProtocol.establishConnection(NSProtocol.java:672)
  at oracle.net.ns.NSProtocol.connect(NSProtocol.java:237)
  at oracle.jdbc.driver.T4CConnection.connect(T4CConnection.java:1042)
  at oracle.jdbc.driver.T4CConnection.logon(T4CConnection.java:301)
  ... 7 more
Caused by: oracle.net.ns.NetException: The ssl protocol specified is not supported.
  at oracle.net.nt.TcpsConfigure.configureVersion(TcpsConfigure.java:181)
  at oracle.net.nt.TcpsNTAdapter.setSSLSocketOptions(TcpsNTAdapter.java:146)
  at oracle.net.nt.TcpsNTAdapter.connect(TcpsNTAdapter.java:121)
  at oracle.net.nt.ConnOption.connect(ConnOption.java:123)
  at oracle.net.nt.ConnStrategy.execute(ConnStrategy.java:337)
  ... 12 more
Caused by: java.lang.IllegalArgumentException: SSLv2Hello
  at com.ibm.jsse2.mb.a(mb.java:6)
  at com.ibm.jsse2.lb.<init>(lb.java:16)
  at com.ibm.jsse2.jc.setEnabledProtocols(jc.java:245)
  at oracle.net.nt.TcpsConfigure.configureVersion(TcpsConfigure.java:177)
  ... 16 more

This difference between Sun's and IBM's JVMs is documented. I don't want to use SSLv2 (which is considered insecure now) in any form anyway, so I added another property:

props.setProperty("oracle.net.ssl_version", "3.0");

Enforcing SSL or TSL on the listener side in listener.ora doesn't do the trick. I've written some enhanced version of the test to simulate more accurately what I believe WAS is doing while establishing the connection:

import java.util.Properties;
import java.sql.*;
import javax.sql.*;
import oracle.jdbc.pool.OracleConnectionPoolDataSource;

class OracleSSLTest {
  public static void main(String[] args) throws Exception {
    DriverManager.registerDriver (new oracle.jdbc.driver.OracleDriver());
    String url = "jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS=(PROTOCOL=tcps)(HOST=oracle)(PORT=2484)) (CONNECT_DATA=(SERVICE_NAME=TESTSSL)(SERVER=DEDICATED))" + 
    "(SECURITY=(SSL_SERVER_CERT_DN=\"CN=testssl,C=PL\")))";
    Properties props = new Properties();
    props.setProperty("user", "testssl");
    props.setProperty("password", "testssl");
    props.setProperty("javax.net.ssl.trustStore", "client.jks");
    props.setProperty("javax.net.ssl.trustStoreType", "JKS");
    props.setProperty("javax.net.ssl.trustStorePassword", "password");
    props.setProperty("oracle.net.ssl_server_dn_match", "true");

    props.setProperty("oracle.net.ssl_version", "3.0");
    Connection conn = DriverManager.getConnection(url, props);

    System.out.println("Great success!");

    OracleConnectionPoolDataSource ds = new OracleConnectionPoolDataSource();
    ds.setURL(url);
    // setting username and password once again through datasource methods seems to be required as exception is thrown otherwise
    ds.setUser("testssl");
    ds.setPassword("testssl");
    ds.setConnectionProperties(props);
    PooledConnection pc = ds.getPooledConnection();

    System.out.println("Another great success!");
  }
}

Since the test run without an error also with ojdbc14.jar, I switched to the Integrated Solutions Console to create the data source with the above properties. One thing to keep in mind is that the properties to be passed to the OracleConnectionPoolDataSource factory must be defined as a value of a newly created custom property connectionProperties in the following form:

javax.net.ssl.trustStore=client.jks; javax.net.ssl.trustStoreType=JKS; javax.net.ssl.trustStorePassword=password; oracle.net.ssl_server_dn_match=true; oracle.net.ssl_version=3.0

Another problem one may encounter is using an anonymous cipher. Trying to limit ciphers probed during the handshake with the statement:

props.setProperty("oracle.net.ssl_cipher_suites", "(SSL_DH_anon_WITH_3DES_EDE_CBC_SHA, SSL_DH_anon_WITH_RC4_128_MD5, SSL_DH_anon_WITH_DES_CBC_SHA)");

Effects in the following exception:

Exception in thread "main" java.sql.SQLException: I/O Exception: IBM's Client TrustManager does not allow anonymous cipher suites: SSL_DH_anon_WITH_3DES_EDE_CBC_SHA
  at oracle.jdbc.driver.T4CConnection.logon(T4CConnection.java:421)
  at oracle.jdbc.driver.PhysicalConnection.<init>(PhysicalConnection.java:531)
  at oracle.jdbc.driver.T4CConnection.<init>(T4CConnection.java:221)
  at oracle.jdbc.driver.T4CDriverExtension.getConnection(T4CDriverExtension.java:32)
  at oracle.jdbc.driver.OracleDriver.connect(OracleDriver.java:503)
  at java.sql.DriverManager.getConnection(DriverManager.java:562)
  at java.sql.DriverManager.getConnection(DriverManager.java:155)
  at OracleSSLTest.main(Test.java:15)
Caused by: javax.net.ssl.SSLHandshakeException: IBM's Client TrustManager does not allow anonymous cipher suites: SSL_DH_anon_WITH_3DES_EDE_CBC_SHA
  at com.ibm.jsse2.eb.serverHello(eb.java:199)
  at com.ibm.jsse2.eb.a(eb.java:54)
  at com.ibm.jsse2.db.m(db.java:208)
  at com.ibm.jsse2.db.a(db.java:259)
  at com.ibm.jsse2.jc.a(jc.java:271)
  at com.ibm.jsse2.jc.g(jc.java:403)
  at com.ibm.jsse2.jc.a(jc.java:401)
  at com.ibm.jsse2.j.write(j.java:10)
  at oracle.net.ns.Packet.send(Packet.java:385)
  at oracle.net.ns.ConnectPacket.send(ConnectPacket.java:173)
  at oracle.net.ns.NSProtocol.connect(NSProtocol.java:283)
  at oracle.jdbc.driver.T4CConnection.connect(T4CConnection.java:1042)
  at oracle.jdbc.driver.T4CConnection.logon(T4CConnection.java:301)
  ... 7 more

IBM documents a way to implement own TrustManager and override the default with SSLContext.init() method for your own code, but it obviously doesn't hit the spot. There is another solution in the documentation that suggests to add the line com.ibm.ssl.skipDefaultTrustManagerWhenCustomDefined=true at the top of the ssl.client.props file and define the custom trust manager with com.ibm.ssl.customKeyManager thereabouts, but it doesn't work for me.

Tuesday, September 1, 2009

Hello world!

Hello indeed.

In the conversations with my colleagues (and in the course of introspection) I realized that the reasons of founding this blog are somewhat fuzzy even to me. The best explanation I came up with — i.e. that it pretends to be homologous to skilful developers' blogs I regulary read — does not satisfy my inner need of exploring the heart of the matter.

So, after fair amount of rumination, I've formulated a short list of things I expect of this investment of time.

Don't get me wrong: I believe that in the field of software development you cannot assume positive expected monetary value from that sort of an investment, unless you are an evangelist or in some another way connected to the vendors of the software you write about. That's the joy, not money, you gain.

Let's face the truth — an employee of an ISV sparsely may tell a good word on the big company's proprietary product. However, there is a tendency to render a pretty positive opinion on an open source solution, where any bugs one may encounter can be fixed by patching the sources. That's not the feature nor quality, but the expectations and possibilities gap that matters. Similarly, the intention of this site is not to replace a pile of documentation written by professional technical writers. It is to present an independent view on the development process; and the knowledge not mean to be arbitrary correct, but open to correction and enhancement.

Through the previous digression I introduced maybe the main topic of this weblog's content. I owe a great debt to all the bloggers and forums' users that led me out of all these hopeless situations, when the stacktraces were dozens lines long and there was no hope. I don't know if it is hacker ethic's knowledge sharing principle, an egocentric will to show off or become influential, evolutionary-coded altruism or feel of guilty. You must go ask my psychotherapist if I'll ever get one. Only thing I know is that I want to quickly google a solution whenever I encounter a problem that's not my fault. So if the solution cannot be found — and I accidentally happen to work it out — I feel obliged to post it.

See, I don't know any country with a software industry employees union, but the profession nevertheless seems to be one of the most corporative.

Besides my findings that I hope will be helpful to the readers (and to myself as soon as I'll start to forget the stuff) I'm going to post my thoughts on books I read, talks I saw, projects worth to be promoted and so forth. Furthermore, I wish I would write something more architecture-level from time to time. That means posts without a LOC.

It would be really cool if there was any feedback, avid discussions in the comments, clever answers to the rhetorical questions I ask, gifts, money, hugs & kisses, but I don't really anticipate any of these, at least initially. I'm not really into this whole 'blogosphere' thing and have never frequently commented on blogs I read. So I won't be suprised if neither do my readers.

I think of programming as of creating aesthetically compelling structures in order to organize some segments of this chaotic matter we are struggling with. This weblog is intended to do the same with the topic of software development, where the phenomena of increasing entropy is visible as nowhere else.