EJB 1.1 and disk io - java

I have a question about EJB 1.1 (yes really that old ... - please dont kid me...)
So the question is one of the old ones: Why should I not do disk io within EJBs? Especially reading files.
To be more precise the use case: Its all about one file that is needed as a template for some special data export.
So it is:
one file
very rarely changed (for example within a special maintanance time)
rarely read
no heavy load
Is there any reason, why not to read that template file from disk?
Are there any technical restrictions like an ForbiddenOperationException when I try to do disk io within an EJB. I already run a test and reading and transferring is working just fine. Is that behaviour different within EJB 2.x or 3.x?
Thanks a lot!

This restriction is in the specification to allow for clustering of EJBs, which is easier if the EJB is self-contained and does not rely on the outside environment such as the file system.
Accessing the file system should work fine however, if you truly want to comply with the spec you could bundle the file inside the EJB jar and access it from the classpath using Class.getResourceAsStream.

From EJB Restrictions :
Enterprise beans aren't allowed to access files primarily because
files are not transactional resources. Allowing EJBs to access files
or directories in the filesystem, or to use file descriptors, would
compromise component distributability, and would be a security hazard.
You can pack file in a JAR so that you can read it with getResource() or getResourceAsStream() & can change, redeploy independently.
Else, if you haven't encountered any issues with your current approach, then its fine, but isn't recommended in accordance with the specification.

Why not store it in database as a blob?
then you can have an admin webapp to change it from browser
and you can use ldap to authenticate/authorize the webapp
oops, sorry for making life so complicated

Related

Reading a file from within App Engine module

I am trying to read a static file from within App Engine module that is placed inside WEB-INF directory.
...
File file = new File("WEB-INF/somestaticfile.ext);
...
It perfectly works in cloud environment, however, in development server it ends up with FileNotFoundException.
I build and run the app with the aid of maven and it seems that it is also needed to prepend a directory representing the module inside the project's EAR hierarchy so that the file would be found.
...
File file = new File("modulename.war/WEB-INF/somestaticfile.ext);
...
This works in local development server but not in cloud environment.
I believe that there is a way how to read a file that would work in both cloud and local environment. Any advice would be appreciated.
I have spent some time to figure it out and here are solutions I have found. If you have your resources placed on classpath then you can access them as follows from both cloud and local dev server.
getClass().getClassLoader().getResource("resourceName");
or
getClass().getClassLoader().getResourceAsStream("resourceName");
However, if your resources are place somewhere else (e.g. WEB-INF), the only way I have found is by means of javax.servlet.ServletContext#getResource(String) or javax.servlet.ServletContext#getResourceAsStream(String) that also work in both environments. This solution is perfectly OK if you access resources from web layer of your app but if you need to access them from other layers (e.g. service layer), it is not probably a good idea to introduce a dependency to Java Servlet API to that layer.
Since I am using Spring, I decided to load resources via org.springframework.core.io.ResourceLoader#getResource(String) that returns a resource abstraction whose concrete implementation depends on the application context type and a resource path prefix. For applications running in a web container, the actual implementation uses ServletContext methods under the hood but you are shielded from it.
If you do not use Spring, it should not be a big deal to implement your own resource abstraction based on ServletContext.
If anyone could provide other solutions, feel free to do so.
An excellent resource, as always, are the Google developer documents:
https://developers.google.com/appengine/docs/java/config/appconfig
That said, to help others in future, I will summarize some relevant points that I think generally relate to the question (since I can't see what is happening your specific environment).
App Engine serves static files from dedicated servers and caches that are separate from the application servers. Files that are accessible by the application code using the file system are called resource files. These files are stored on the application servers with the app.
By default, all files in the WAR are treated as both static files and resource files, except for JSP files, which are compiled into servlet classes and mapped to URL paths, and files in the WEB-INF/ directory, which are never served as static files and always available to the app as resource files. You can adjust which files are considered static files and which are considered resource files using elements in the appengine-web.xml file. The element specifies patterns that match file paths to include and exclude from the list of static files, overriding or amending the default behavior. Similarly, the element specifies which files are considered resource files.
You mentioned that there seemed to be a disconnect between the development server and deployment. Without diving into Maven, my first thought was to look at path patterns. As they note on the Google Developers documentation, path patterns are specified using zero or more and elements. In a pattern, * represents zero or more of any character in a file or directory name, and ** represents zero or more directories in a path. Files and directories matching patterns will not be uploaded when you deploy your app to App Engine. However, these files and directories will still be accessible to your application when running on the local Development Server. An element overrides the default behavior of including all files. An element applies after all patterns (as well as the default if no explicit is provided).
Hope that helps provide a general perspective. If you find a specific solution to the issue and can share it here, please do!

How to monitor file changes within a Java EE application?

Is there a portable way of monitoring a file for changes from a deployed application?
As a practical example, suppose that I have an application deployed in a Glassfish AS. Then, as the application runs, I deploy a configuration file inside /META-INF, which will be read by some Thread from my application.
So, how to implement this? How to monitor a file (or a directory, for that matter) for changes?
Java7 has a platform independent solution to monitor files in the filesystem:
http://docs.oracle.com/javase/7/docs/api/java/nio/file/WatchService.html
Here is a short tutorial on how to use it:
http://docs.oracle.com/javase/tutorial/essential/io/notification.html
But as jtahlborn has correctly said, if the container does not explode the .war file, there is nothing to watch.
I think it would be impossible to provide such a mechanism. You are assuming "/META-INF" is on the file system, but i don't believe there is any requirement for a Java EE application to be exploded to the filesystem. (yes, many app servers do that for a variety of good reasons, but i'm pretty sure that is not a requirement).
Classloaders cache heavily and a resource when first read is not updated anymore from the underlying filesystem.
Regardless, you are not allowed to access and manipulate the file system in pure Java EE. The reason is simple - if your thread is migrated to another node (for clustered serveres) your files will not be available anymore. The container must know about these things so it can handle them properly, and filesystems are not one of "these things".
Please check the answer from #jtahlborn. If you do have access to the filesystem, then you have two choices:
The portable inefficient way is to periodically poll the filesystem and check for changes, either by checking the modification date or CRCins the file (slower)
The efficient way is to use the native OS functionalities to be notified when the file changes. Check out libnotify. It's going to require local native libraries, however.

Disk storage in a Java EE application

I have Java EE app in which I want to small little amount of data to disk, eg just user/passwords.
I dont want to go through the hassle of integrating with a full db for this little amount of data.
Is there a standard way to access the file system and a standard folder where web applications can store their data on disk, other than using a database?
Note:
I am not using EJBs. It's a web application using Servlets.
You could consider using the preferences API to store this data - it's available on Java EE as well.
Use a simple Java based database, like HSqlDB or h2. The setup won't be that complicated compared to a heavyweight DB. The key advantage this will give you is managing concurrent updates, which you would have to code yourself if you use direct file access.
File access has always been a controversial activity within EJB-based applications because of the restrictions placed upon bean providers by the EJB specification. The part of the specification relevant here is under the section entitled Programming Restrictions, and it states the following about accessing the filing system.
An enterprise bean must not use the
java.io package to attempt to access
files and directories in the file
system.
This is a fairly specific statement, and is followed up by a short explanation of why this is the case.
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.
While this explanation highlights a key reason for not using file I/O, I think that there is much more to this. However, although this is a well known restriction, actually finding more information on this is a time consuming task. So, in the quest for knowledge, I did some digging and came up with the following reasons why file I/O is "a bad thing"TM.
The WORA mantra of Java and J2EE means that there might not actually be a filing system to access. I've seen various comments saying that the J2EE server might be running on some device that doesn't have a filing system, or the application server doesn't have access to the filing because it's deployed in, for example, a database server. Although this is a valid reason, I don't think that this applies to most projects.
Access to files isn't transactional. Yes, typically, files aren't transational resources and when building enterprise systems, you usually want to be sure that some information has been correctly and accurately stored, hence the use of relational databases and the like.
Accessing file systems is a potential security hole. If we look at how other resources (e.g. JDBC DataSources, JMS Topics, etc) are accessed, it's usually through JNDI. To ensure that only authorised parties can access these, we typically have such resources protected by some sort of authentication mechanism, be it a username/password combination, or an SSL certificate. The problem with filing systems is that they are much more open and it's harder to control access. One solution is to lock file access via the operating system, and another is to use the Java security model to restrict access to only a specific part of the disk. If you are going to access the filing system from your business components, then locking down access will help to make the system more secure and resilient to attacks.
So then, how are we supposed to access files from EJB? Many people advocate the use of an intermediary Java class to wrap up the file access, believing that the EJB specification only disallows access from the bean class itself. Is this true? I'm not convined because all the same reasons apply. The specification itself presents an answer, and that answer is to use a resource manager so that we can treat file access as a secure, transactional, pooled resource. One such implementation is a J2EE Connector Architecture (JCA) adapter that you write, deploy and configure to access your filing system. In fact, some vendors have already built JCA adapters that access flat files and these are particularly useful if you have to access the outputs of legacy, mainframe systems.
Of course, many types of file access can be worked around. For example, configuration information can be placed in LDAP, JNDI, a database, or even properties files delivered inside your JAR files that get loaded as a resource through the classloader. In those circumstances where accessing files is a requirement, then other solutions include loading the file through the servlet container, having it sent to the EJB tier via messaging, downloading the file from a webserver through a socket connection and so on.
These are all workarounds for the programming restriction but at the end of the day I think you have to be pragmatic. Many projects do utilise file access from within the EJB tier and their solutions work. Although the EJB specification imposes a restriction, in reality many vendors choose not to enforce this, meaning that using the java.io package for accessing files is possible. Whatever solution you come up with, you should ideally keep the specification in mind. It's there to help you build portable and upgradable applications, but pragmatism should be employed. Hopefully a future version of the EJB specification will address this issue in more detail and this controversy will become a thing of the past.
Credit for above goes to: Simon Brown
In addition it is never a good idea to keep passwords on your site. Most security references tell you it is OK to keep a hash of a password that you can check against. If somebody breaks into your site, then he could retrieve all the passwords for all users.
Is there a standard way to access the file system and a standard folder where web applications can store their data on disk, other than using a database?
There's the java.io.File API, but the Servlet or the Java EE specifications do not provide a standard directory where you may persist files for a lengthy duration. At the very best, the javax.servlet.context.tempdir attribute may be used to locate the location of the temporary files directory, from the ServletContext.
The rationale for not supporting standard file directories is due to the inability to predict whether the container would be able to access a file system in the first place. Your container might be running off an embedded device in the first place to begin with, that might rely on a SAN or another remote file system for persisting files.
In addition, using the File API in EJBs is frowned upon, due to the non-transactional nature of file systems, so there is no similar concept of working directories and files.

Storing and editing configuration for Java EE applications

UPDATE: See my blog post on this topic about a year after this was written: http://blog.ringerc.id.au/2012/07/java-ee-7-needs-improvements-in-app.html
... for references to the Java EE 7 planning discussion on this topic.
I've mostly finished writing a small Java EE 6 application, and am in the process of replacing the hard-coded preferences with a proper dynamic configuration interface.
I'm not sure how - or, more specifically, where - to store settings. There must be some obvious, "standard" way to do this that's expected to "just work" across various frameworks and containers, but for the life of me I cannot find it.
What I want is a simple way to load and store settings, one that works across different app servers and OSes, doesn't require any confguration by the user, and actually works properly. The Java Preferences API would be ideal - but seems broken under Glassfish 3.1.
Options for storing configuration would theoretically include:
Using context-parameters from the container environment
Storing them using the Java Preferences API
Reading/writing a properties file ... somewhere
Using JPA to store them in a JavaDB provided by the container
Putting it in a properties file that's loaded off the classpath
Using system properties to set configuration options, or path to a .properties file
This would seem to be a basic requirement that'd be well catered for in an environment where the container supposedly provides you with all the core services you might need - but all these approaches have issues.
A bug in glassfish renders (1) unworkable, and in any case the Glassfish web admin user interface lacks any way to configure context parameters, so you have to use `asadmin' and some less than lovely command line syntax to do it. Context parameters can only be accessed via the ServletContext - which isn't accessible in a consistent way between frameworks like JSF2, JAX-RS, and raw servlets - but at least Seam Servlet handles that.
What appears to be another bug in glassfish was a library version conflict between the deployed app and Glassfish breaks (2). The preferences backend fails to flush preferences to disk, so the stored preferences data is lost when the application server is restarted. The Java Preferences API also seems to be considered a J2SE/desktop thing, despite its inclusion in the Java EE 6 specs.
(3) might work - but there's no way to know where your app has read/write access on the file system and where it should look. You can't make this configurable, as it becomes a chicken-and-egg problem then. Various platform-specific guesses could be applied, but would break in the presence of a SecurityManager.
(4) would work, but it's nuking a fly. It requires that a JavaDB service be running and forces the user to make sure the JDBC and pool resources in the app server are configured properly. It's big and complicated for a simple job, and entity modelling isn't a lovely fit for preferences storage anyway, as it'll mostly land up being key/value structured.
(5) would work, but requires users to know where to put the config file where it'll be found under various different app servers. It also makes it hard for the app to provide any kind of configuration UI because it can't necessarily find the local path to the config file or open it for writing, especially in the presence of a SecurityManager.
(6) would also work, but forces the user to configure the configuration system before they can configure the application. Needless to say, that doesn't excite me, given how relatively complicated deploying the app and creating the resources already is for users who don't already know Glassfish/EE.
So ... how are you handling configuration and storage of options? Have you found a way that lets you "just do it" without the user having to configure anything to allow your app to store its configuration?
The problem with the preferences API was caused by the inclusion of jaxb and stax implementation jars on in the application's war, pulled in by jersey-json . With these excluded (as they're provided by the app server anyway) the preferences API resumed functioning correctly.
It looks like the prefs API with custom UI for setup appears to be the best way to go.
Though not the environment you spoke about: http://www.osgi.org/javadoc/r4v42/org/osgi/service/cm/ConfigurationAdmin.html

FileIO from an stateless session bean

I need to read and write xml files to disk from a stateless session bean running in JBoss. What is the preferred way of doing this?
Right now we are accessing the file system using the java.io classes.
I found a simple file system RAR example and have got that working but it may be more buggy than just using java.io directly.
If you check that Programming Restrictions section of the EJB Spec you'll find the following:
An enterprise bean must not use the java.io package to attempt to
access files and directories in the
file system.
If you can find a better, possibly secure and more importantly, transactional way of doing it, please reconsider. We have a system that stores PDF documents as blobs in a database and then serves them to the users by email or servlet.
The JBoss JCA based FSManagedConnectionFactory isn't too bad. It is JNDI based and likely to work in more instances than just hacking around java.io
If you properly close the file and clean up, you can use anything you want.
I would use an XML parser to read or write XML files, though, it is safer.
The complicated way is to write a ejb client that reads the file, or set up an xml datasource somehow. In reality, nothing bad will happen if you use java.io in the session bean. However, if you are using clustering and/or will migrate the servers, then you have to take care of where your beans are running and which one will be invoked.
The simplest "batch" solutions is to take one machine out of the cluster and run the "batch" applications there.

Categories