26

I would like to know how can I access the file system from an EJB 3 bean?

I searched the Internet on the subject and haven't found a good answer.

Some suggest using the java.io/java.nio even though the specification prohibits this usage. Most application servers seem to allow the access to this API anyway.

Another idea would be to use an JCA connector to access the file system or a LDAP directory.

What I want to do this to avoid the use of BLOB in the database when a simple file would be a much better solution in terms of performance and used resources.

How would you solve this problem?

Pierre Thibault
  • 1,895
  • 2
  • 19
  • 22
  • 1
    You don't have to have a BLOB in the database. SQL Server 2008 supports filestream storage that essentially dumps the file into a folder on the DB server but exposes it through the database. http://blogs.msdn.com/rdoherty/archive/2007/10/12/getting-traction-with-sql-server-2008-filestream.aspx – pjp Aug 31 '09 at 16:30

4 Answers4

10

The reason that you are disallowed from file system access in EJBs is that you have no control over how your application runs within a (Java EE) Container. For example, your application may be run across a cluster of servers, in which case saving some object to a directory on one server is likely to be of little use. (You may have a network file-system of course, so the restriction may not apply).

One option may be to use the JNDI implementation which comes with your Container. You will likely be able to save a raw byte[] array at some JNDI location, so you could always save down the serialized form of the object:

ByteArrayOutputStream baos= new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(myObj);

//Now save into JNDI
new InitialContext().bind("path/to/myobject", baos.toByteArray());

This can be looked up later and re-converted into your object:

byte[] bs = (byte[]) new InitialContext().lookup("path/to/myobject");
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bs));
MyObj myObj = (MyObj) ois.readObject();

Alternatively you could use the java.beans persistent XML (i.e. XMLDecoder, XMLEncoder) to encode your instance as an XML string an save that into JNDI.

oxbow_lakes
  • 133,303
  • 56
  • 317
  • 449
  • Is this the recommended way of writing files from a EJB? Will the file be available to every node in a cluster (I think JNDI indeed is clustered so probably yes)? Last reading to (or writing from) JNDI is transactional? – Mike Argyriou Jul 29 '15 at 09:09
  • "you are disallowed " - you are not longer disallowed to access the filesystem and it was NEVER the intend that this only applied to the EJB specification. Whoever wrote that at the time was deluded that EJB would be the foundation of all of Java EE and therefor pretty much equalled Java EE. – dexter meyers Sep 04 '15 at 10:16
9

If you know you will never cluster your application (or that you will be able to network-map the drive) then just use java.io.*.

Be sure to introduce proper configuration regarding the root location of your files storage.

flybywire
  • 261,858
  • 191
  • 397
  • 503
  • +1 This answer is just *common sense*. If the file is filled by another program (that doesn't conform EJB) there is no faster and *clear* way to do it. – ATorras Aug 31 '09 at 14:30
  • 3
    By writing an application that does not adhere to the Java EE spec, you cannot be sure that it is portable and maintainable. For example, in 12 months time you may have left this project behind with a large surprise for the poor person given the task of clustering your app. Or porting it to a different container. – oxbow_lakes Aug 31 '09 at 14:34
  • 8
    *"If you know you will never cluster your application"* - if you find that you can see into the future, you may think that there's a more lucrative career beckoning in the gambling industry. – oxbow_lakes Aug 31 '09 at 14:36
  • 1
    +1 I think it just depends on the requirements. BTW I have sent many CVs ;) – ATorras Aug 31 '09 at 15:21
  • 9
    @oxbow_lakes designing for a future you don't need today or tomorrow is also a bad practice. I've seen people completely overcomplicating their design to be "flexible in the future", but all that supposed flexibility wasn't used once after a life-span of 10 years. All this time it deed slow all kinds of tasks down. As always, use common sense. – Mike Braun Nov 26 '12 at 09:49
  • 2
    Frequently these complicated now for future techniques end up not even being a good fit in the future, and are never used in favor of a huge rewrite anyways. – le3th4x0rbot Jun 14 '13 at 18:55
5

Encapsulate your access to file data. Then you could use any of the methods outlined above. Even use a database. Measure the performance of your system. If it meets requirements then you are done. If not your file access is localised in one place and you can substitute a different solution. Same benefit if the software has to be ported to another container and/or has to be maintained by someone else.

Conor
  • 2,419
  • 3
  • 19
  • 18
1

Plain file access is not transactional in nature. Unless you build in support for transactional operations (I'm clueless on how - this is the job of a resource manager), you will have to worry about transactional semantics of the operation that you are performing. If you do build in transaction support, there is very little you would have gained in performance (some of the loss in performance in databases, is due to all the bookkeeping done by the resource manager). And don't forget transaction management's close cousin - concurrency. Unless you start writing into a new file for every request, concurrency issues will more or less bite you.

You will find a lot more information in the Sun Blueprint's FAQ on EJB restrictions.

Unless you are in the clear with a good technical justification, you should not attempt to access the filesystem from EJBs. A very good example, would be a logging (not auditing) framework - there is relatively less harm in accessing the file system to write log files, given that logging does not have to be a transaction operation i.e. you dont need to rollback writes to a logfile; not that it is acceptable to have partial writes.

Vineet Reynolds
  • 76,006
  • 17
  • 150
  • 174
  • Caching files locally via a Singleton/timer is another example of an operation that's pretty much always safe. – Mike Braun Nov 26 '12 at 09:52
  • 1
    "Unless [...] you should not attempt to access the filesystem from EJBs" - there is absolutely no specific reason why this should only hold for EJBs. One should be cautious when doing IO from *every type of bean*, not just beans that happen to be EJB beans. – dexter meyers Sep 04 '15 at 10:20