Today one person told to me that "J2EE programmers do not write to files". Why can I not write to files from within a J2EE container (for example from JBoss)? What is wrong?
You should do everything within the J2EE container itself: you can have no certainty that you will have any consistent access to the filesystem. There are many reasons for this, the most obvious being that applications running within a container will have:
- no certainty that any subsequent invocation of an EJB would even be on the same physical server with access to the same files/filesystem (e.g. upon clustering)
- no possibility of interfering with each other (multiple applications attempting to write to the same file)
- no security issues (one app writing confidential data which another app could read)
You should also assume that you shouldn't:
- create your own threads (the container will manage this for you; if you create your own you may starve other applications in the container of CPU time)
- use socket-IO (also has security issues)
Even if you have access to the filesystem, with distributed systems you can't be sure that the next time a method is called, it will be handled on the same machine where the file was written.
Because the J2EE spec doesn't offer an API to write files. Of course, you can just use the normal Java IO API to create files but you must make sure that this code is thread safe, that someone cleans up the files, that the file name is passed on to the next bean, that the file is migrated when your bean is moved to another node in the cluster, etc.
So while you can do it, in practice, you'll encounter lots of small problems which make handling files in J2EE really hard.
If your instance is not clustered or one can guarantee that all instances can use a network drive then its not really a problem to use the File apis to read/write files. However care must be taken to get paths right and clean up as appropriate. Often there are not any real needs to write files so think about it again. The main reason most people give is that in a cluster different servers wont see the same file bcause paths change and so on. In the end most many small apps dont run in such a cluster...
Per J2EE specifications, EJBs are strictly prohibited from accessing any external resources by any means other than through a "resource manager" (JDBC, JNDI, JCA, etc) and this includes especially access to the local file system through classes of the java.io
package. Additionally, nor can a ClassLoader
be used for such access, such as to load a properties file from the application's classpath.
Reasons for this have already been given in other answers:
- Security issues
- Portability issues
- Clustering issues
- Threading issues
Ultimately, the best resource for these matters is a database.
You should consider a Filesystem as a Enterprise Information System (EIS). Then you can create a ResourceAdapter which accesses this EIS, similar to a JDBC adapter which accesses a database. The spec is here: http://java.sun.com/j2ee/connector/download.html . This means file access is possible, but much more complicated. This spec even allows you to create some sort of "threads" called Work.
In order to inter-operate with a legacy non-j2ee systems, you occasionally have to do "bad things" like socket i/o, writing to files, etc. In the best of all worlds the j2ee spec would be followed strictly, but people get away with non-j2ee stuff all the time for the sake of expediency and getting the job done. There are ways to pull these things off safely and thoughtfully.
The best page to look at is this one: http://java.sun.com/blueprints/guidelines/designing_enterprise_applications/ejb_tier/qanda/restrictions.html
It covers in detail the restrictions over the J2EE programming model.
Apart from the point mentionned above Security, Portability, Clustering, Threading also consider transactions and error handling (File systems are not transactional).
There is however no black magic happening in the JVM and you can create files (as long as you have the corresponding rights), use static variables, and create threads if you know what you're doing.
Better take the time to understand why these restriction are usually suggested, than to jump and write a JCA connector for the sake of being compliant.