So, the current project I am working on will be running inside of a J2EE container, behind some Message Driven Beans (MDBs). The requirement is that our application must grab some files from various locations… FTP servers, Content Management systems, file system shares, etc…
So, when the team member that is working on these components said that we cannot us the java.io package inside an EJB, my initial reaction was “BS! who says that?!?!”. At which point I was pointed at this:
From page 511, EJB 3.0 Proposed Final Draft - ejbcore:
- An enterprise bean must not use the java.io package to attempt to access files and directories in the file system.
The file system APIs are not well-suited for business components to access data. Business components
should use a resource manager API, such as JDBC, to store data.
- An enterprise bean must not attempt to listen on a socket, accept connections on a socket, or use a socket for multicast.
The EJB architecture allows an enterprise bean instance to be a network socket client, but it does not
allow it to be a network server. Allowing the instance to become a network server would conflict with
the basic function of the enterprise bean— to serve the EJB clients.
WTF is up with that!?!?!
I can understand the underlying concepts… managing resources can be hard, and J2EE is all about pushing the management of resources to the container. Thats fine to an extent, but I have some issues with the above statements:
- It is too specific on the technology, but vague on the reason. I’m sorry, but just because a technology is not “well suited” does not mean I “must not use it”. There are situations where I may need to use it, but now it is a Taboo. Doing a quick google indicates that there are a number of potential reasons, most revolving around blocking versus non-blocking operations, where blocking operations, such as reading from/writing to a disk). I feel that as long as you understand and are prepared for the consequences, this should not be a problem.
- It is vague overall. So, can I use this inside of a component, as long as it is not a “Business Component”? And what does that really mean? Can I use System.out? What about Logging? They use Java.io… are they OK?
- It has not been updated in EJB 3.0. If this is such a problem, why has it not been updated to take into account java.nio?
I’m confused. I would love to hear what other people think about this, as it does not make any sense to me. Can anybody answer these questions?
I know for me, I couldn’t care less that the spec says don’t use java.io. If you know how to use it, and are aware of what the issues are with using it, than use it. Unfortunately, there is a political cloud over this. There are people that believe that the spec cannot possibly be wrong.
If we do use java.io in our system, it will be inside of a component, not an EJB directly. And if we have to we can always use java.nio
In the end, I feel that the spec is just poorly worded, and is in dire need of an update.
andy | 24-Feb-06 at 3:55 am | Permalink
I would like to point out that this is not a new addition to the specification. And there are a number of reasons why java.io might reduce portability. For one the specificaiton does not percisely define the appserver’s threading model and threading dynamics. If you listen on a socket and work with incomming connections then you must also deal with threaded programming (which it also declines as your domain elsewhere). I’ve seen a number of instances where poorly threaded code worked on one appserver and not the other (often due to chance or race conditions). So there are rationales and reasons (such as portability).
The “spec” portable and correct way to say open up a socket, read/write a file, etc is to create a JCA component. A JCA component has a portable way of defining “work” and the underlying transactional semantics of that work. Again there are some rhymes and reasons (and even counterarguments) for this, such as lets say you write a file, then attemt to send a JMS message “file written name”+name but the JMS server is down (must not be using JBoss
) and so the transaction roles back but now you have a file sitting around that no one knows about (that you would like to have “never written” or “undo” aka “delete”). A JCA component gets proper notification. A counter argument to this is the ability to use the SessionSyncronization (SFSB) to pull this off.
However, a rule of thumb is that the core spec tries to draw a line between the system and application programmer (one of those lines is resource management), and favors portability in some places over empowerment. stateless session beans are REALLY inapporpriate for threading (cause they are pooled any your lock on any given instance is method invocation long), and um putting that in an “entity” would probably be pretty ill advised. If you’re willing to step outside the spec a little and are in JBoss’s EJB3 container (which there is probably pretty close to a 1 in 3 chance that this is the case) then you could use ServiceBeans. Service Beans essentially have the same thread model as a default thread model servlet (all threads by same instance…). They look smell and feel like SLSBs and you can also give them an MBean name (they are a little fatter than model JMX MBeans). Same annotation semantics, etc. MBeans have tradtionally been how a lot of people did potentially non-portable code in JBoss that they wanted to control (for instance). This is really a revision of that.
So use good judgement and do what makes sense for your app. Also I strongly suspect the nio was just a cut and paste error. I don’t know if it can be corrected at this stage, but I’ll mention it.
Matt | 24-Feb-06 at 8:08 am | Permalink
Thank you for that Andy, it helps a me a little bit, but I am still not quite sure I understand the real reason for not allowing file I/O. This may be due to the poorly worded nature of the spec, as I am still not sure that it is a problem to use java.io inside of a subcomponent or delegate.
As for transactional support, it makes sense to use the JCA when you need to make sure things are properly handled in that scenario. But in my case, all I am doing is reading files from another server/service and storing them in my database. The transactional piece is taken care of by the JDBC layer, for which, I might add, I will need to use an java.io.InputStream to get my binary content into the system…
I would also like to point out that portability is generally not an issue for the enterprise applications developer. We are running WebLogic (sorry) and there is nothing on the road map that indicates this will change. If it does, things will break. Part of the problem with portability in the J2EE spec is that J2EE is designed to allow vendors to provide extensions, which breaks portability. So, I feel that portability is a poor arguement for this situation.
Also, I have never seen, on all the seven or so OS’s and the 4 or 5 containers I have worked in, a problem specifically with java.io. Sure, there have been Socket issues, and there is always the damned threading issues, but not specifically java.io issues.
Jeff Sheets | 24-Feb-06 at 8:39 am | Permalink
Hey Matt,
I’ve often been confused by this too. I know it’s been in the spec for as long as I can remember, and I’ve often referenced this post for clarification:
http://weblogs.java.net/blog/simongbrown/archive/2003/10/file_access_in.html
Too bad it doesn’t really clarify
I’ve seen some creative ways to get around this that I’m not sure are any better. One project someone had wrote a java client that connected to a Queue and processed a ReadFile message by writing the file back to another JMS Queue/Topic. Essentially it was an MDB but ran outside of the container. The same thing could probably be accomplished with Spring’s new JMS Listener beans (name escapes me).
I’ve also seen people use a DAO-type object to read/write to the file. But I don’t think this technically gets around the EJB restriction, since the DAO is still called from within the EJB.
So I totally agree that this is a shady area in the spec that nobody seems to have a solid solution to, but the JCA idea sounds promising. I believe that WLS 9.0 will have a MDB-type bean that can watch a file or directory for changes instead of a JMS Queue, which would work for us in many cases…
Bob Lee | 24-Feb-06 at 12:33 pm | Permalink
I’ve run into the exact same dogmatism (over the static/synchronization rules in my case). Those rules are there so your EJB works in a clustered environment (i.e. if you write a file on one server, it won’t be on another necessarily) and so you don’t interfere with the server’s ability to manage resources (for example, you wouldn’t want to make a piece of code complete synchronized). The rules are too drastic. If you understand the reasons for not using file I/O or statics or synchronization in this sort of evironment, there’s no reason you shouldn’t do so where it makes sense.
Matt | 24-Feb-06 at 12:57 pm | Permalink
Bob: I fully agree.
Matt | 24-Feb-06 at 1:07 pm | Permalink
Jeff, Yeah I saw that post too… forgot to mention it. Thanks for that ;).
As I understand the problem(s), it really comes down to the container is not managing these resources for you. Guess what: regardless of what technology you use, JMS Queues or what-have-you, it does not get around it. And I might add, all of the options you threw out were mentioned in our team meetings.