In one of the most pyrotechnic attacks on Stateful session beans I have seen, a new article on onJava.com by Tyler Jewell discusses the true purpose of SFSBs, where they belong in a J2EE design, and the situations where they should not be used. This is article is a must-read.
Read Stateful Session EJBs: Beasts of Burden
I have to say that I agree with Tyler on most of his points. From a design perspective, it really doesn't make sense to use Stateful Session Beans. Consider:
When it comes down to the debate between servlet session and stateful session bean, the servlet session wins out in my mind, except for one point that people always resort to: If you store conversational state in your
servlet session then you can't reuse your EJB's for other types of clients.
I think this point (about multi clients) is flawed. I think different types of clients should also store conversational state locally. If you think about it, conversational state implies a conversation, which in terms
of a UI, it implies some sort of workflow.
The semantics of a workflow will change drastically depending on UI technology a client uses (web vs. rich gui). Therefore isn't it a better design choice to store UI specific conversational state on the client anyway?
For example, if a usecase requires data items A,B,C to execute. And the process of 'accumulating' these data items from the client needs to take place over a short period of time (ie: a client can't input this into a UI
in a single submit), then I think it is better to accumulate this state using some client specific workflow and store it on the client. When all three pieces have been accumulated, then you can just call a stateless
session facade method with the 3 pieces it needs to execute.
I wonder, does BEA's commerce server/personalization server use stateful session beans as a data store? There's a lot of caching going on on top of the entity beans, but they might be doing it right. Haven't looked into it in depth yet.
They are also useful when state should be on a session bean ;-)
Consider the case where you need to construct one of several EJBs that implements the same interface, and the data passed to the constructor (ejbCreate) will affect the later execution of transactional methods. You could accomplish this without SFSBs but you would be passing an odd assortment of parameters everywhere.
The rule that I adopted early on is this: For a web app, no SFSB can exist outside of session scope, meaning that it can't exist before the service() call is invoked, and it is removed before the service() call completes. To accomplish this, we use thread-local storage on the web tier to track the refs to all SFSBs created and use try..finally in a front servlet to make sure everything is cleaned up appropriately.
Another perspective on Cameron's point is to try and identify where the *most appropriate* place for your conversational state should be located. I'm not arguing for completely server side or client side, rather, the state should be located at the tier that does transactional or request demarcation.
If your data needs to be transactionally aware (ie, be notified of when transactions are started, committed, etc.) then the client state should be located on the tier that demarcates the transaction. If a remote client is doing the UserTransaction demarcation manually, then the state should be located on the client (the client will understand the lifecycle and be able to appropriately respond to any commits / rollbacks). But, if TX demarcation is being done on the server side and your data needs these notifications, then the state should be managed in a SFSB.
I think Cameron's argument is very similar (minus the TX aspect). Instead of receiving TX notifications, the data is pertinent to the lifecycle of a server-side request.
Tyler states "...This was the primary intent of SFSBs when they were created."
This may be a stupid question, but how do we know the intent of the original EJB spec designers? Is this intent documented someplace ala The Annotated C++ Reference Manual?
As per the intent of the original EJB spec authors, I made that statement because of two sources:
1) The EJB specification itself eludes to the intent of stateful session EJBs by describing its use as a server side shopping cart.
2) I've worked with 3+ individuals who have influenced the specification over the past three years (two of them on the expert committee) and constantly poll them for advice. In this case, one of them told me that this was the original idea with SFSBs. As with many technologies, SFSBs have grown to serve other purposes than originally designed.
"That's right. You heard it here first. I'm calling Stateful Session EJBs (SFSBs) the J2EE beasts of burden. I don't care for them. I despise them. I really hate them."
Sounds strange. Why now?. EJB has been around for 3+.
Those statements were there just to get your attention ;). But, for the points made in the article, it often takes a couple years to witness all of the mistakes people make with a particular technology before we can write about best-practices of using it. The article is mostly that: best practices in using SFSBs.
In one sentence you mention:
"the state should be located at the tier that does transactional or request demarcation. "
which basically mandates that state should be stored on the server, since practically everyone uses container demarcated transactions (via deployment descriptors), but then in another sentence you say:
"If your data needs to be transactionally aware (ie, be notified of when transactions are started, committed, etc.) then the client state should be located on the tier that demarcates the transaction"
which is by far accounts for a minority of cases (has anyone here ever used the transaction notification features of a stateful session bean???).
If my suspicions are true (that most developers use contianer demarcated transactions and don't need TX notifications), then in fact there is really no argument for using stateful session beans over client side state storage (or DB storage).
ps - perhaps it would help if you gave a simple example of a business case for having data be transactionally aware?
It's possible, but rare. Suppose you were implementing a non-web Java client that used SFSB to track a three step flow. Each step is represented by a SLSB that does the action, conversational related data is stored in the SFSB.
1) Create SFSB on server
2) Execute SLSB m1() with TX Required
2a) Update SFSB data (bean is now part of TX)
2b) Perform Actions
2c) m1() completes
2d) TX commit
2e) SFSB sees commit of TX
3) Execute SLSB m2() with TX Required
3a) Update SFSB data (bean is now part of TX)
3b) Perform acttions
3c) System exception is thrown
3d) TX rollsback
3e) SFSB sees rollback and reverts conversational data.
4) Client can re-execute m2() based upon values of SFSB.
I saw this in an application once (and only once). Anyone else using an architecture like this?
I completely agree with the two "When SFSBs should not be used" points. However, they do not show a flaw in the SFSB model itself, but rather in the way people use it. As for the note about the EJB spec listing shopping carts as a possible use of SFSB - it is fine as long as the cart is transient, and I believe that's what the authors intended (and no, I can't back that belief :).
I am at loss about the "When SFSBs should be used in non-web systems" section. SFSB are not a replacement for client-side state. In particular, a client still has to hold a reference to the session bean. Holding a reference to a local object holding the client state instead isn't different. I can only interpret this statement in the context of the following paragraph, i.e client shouldn't hold *a lot* of state because of some performance issue. Tyler: could you please explain your intent in an isolated case (i.e, without next paragraph)?
As for the final section, "When SFSBs should be used in web systems", I agree with the two points Tyler made. However, I don't think Tyler has "prooved", i.e by making some analytic statement, that these are the only feasible uses. One usecase that I have thoroughly debated with a number of people (and would love to hear some debate about in these forums) is using SFSB as non-persistent model in an MVC architecture where controllers are session beans. You may or may not like this architecture, but it does have wide use and is documented as a "best practice" in places like the J2EE Blueprints. One of the key contracts of MVC is that contollers must have read/write access to model state. One of they key assumptions usually made in the three-tier appraoch is that the middle tier does not contact the front-end tier itself. Such "back-sliding" between the tiers would create many dependencies, and is quite impossible in J2EE. I can't think of any natural way of holding the model data in the web-tier and the controller in the middle-tier without breaking the rules above (although I have seen some attempts at using a Command pattern that goes back from the controller to the web-tier... you don't want to know... :)
I can list many reasons for making Controllers SBs (espiecially in EJB2.0) but it doesn't change the point.
My overall conclusion from the article is that SFSBs should not be used in first cases Tyler listed and should be used in the latter cases. Whether or not you should use them in other cases, such as the architecture above, wasn't discussed - in the sense that no reasons were given not to.
Note about Floyd's points about holding GUI specific data in the GUI:
I agree with your point. This is a reflection of the old problem of drawing the line between the model and the viewer-dependent state in classical MVC designs. Surely, not all of the state in an application is "model". The current sizes of windows, what is the next step in the application process, etc are not neccesarily a "model". Only those parts of an application's state that do not depend on a specific view are model (as allowing multiple views of a single model is a key goal of MVC). IMHO, SFSBs should be used in the MVC architecture outlined above for and only for representing such "model" data, which happens to be non-persistent and therefore inappropriate for entity beans. GUI state is better held near the GUI, and placing such state in the model would be a severe design error (IMHO).
In your example, A, B and C are a viewer specific state, while their accumulation is a part of the model. If it isn't persistent I think it does make sense to hold it in an SFSB.
Just my 2 cents
I must implement a multi-web-app session (like HttpSession's were in the old specs). Our application is composed of n web-apps. Some informations need to be web-app specific (use of "normal" HttpSession), some must be accessibles to others web-apps (like user informations, ...)
In example, if I do in web app1 :
In web app2 I must be able to retrieve 'o' with :
Object o = globalSession.getAttribute("object");
I thought to use a SFSB to implements this "global session", is it a good choice ? This article set doubt in my mind ;-)
I want to comment on Gal's post about why anyone would use a SFSB in a non-web client. The feelings of posters here seem to indicate that the client should just be "fatter" and elminate the bother of dealing with the SFSB. I've seen a couple clients that need SFSBs in this case when they have partially connected clients (clients that come and go quite frequently). They prefer to store session state on the server and then use Handles on the client side as a quick re-connect option. If the local Handle that the client has gets a NoSuchObjectException, then they recreate the SFSB. On some systems, they've had an extraordinary amount of memory, so they set their SFSB cache and timeout limits to be very high. SFSBs rarely timed out and client applications could resume any operation at any later date.
This community is tough to please! As a follow up to the comments posted, the article is not meant to be the end all solution to all SFSB designs. But, what it is supposed to be is a set of basic best practices that novice to intermediate developers should follow. Last month I spoke to 6-8 different BEA clients that were very interested in using EJBs. Their ambition led to overuse of the technology in ways that it wasn't intended for: distributed data caches, transactional data, etc. For those people who understand the true nuances of EJB technology, there are other cases that you could use a SFSB for -- I'm not discrediting those, but I am trying to demonstrate the anti-patterns that exist.
Oh, and for the CMP entity EJB comments, I'm a STAUNCH believer in what entity EJBs can do for an implementation. There are many things that they don't do, but if used properly, they will provide a better design, architecture, and performance than what you will get with Session EJBs & JDBC. Expect my next articles to start detailing how this can happen.
If you are interested in immediate gratification on what I'm referring to, here are a couple of data points:
1) theserverside.com is built using CMP entity EJBs that are configured to be non-transactional and read-only. Have you seen how blazingly fast this site runs? These guys have a solid design: they realized that design isn't about a good domain model, rather its based around transaction granularity, the user interaction, and the accuracy of data. They realized that only 5% of the actions on the site need to be transactional (basically posts) and prepared for that situation. The other 95% of the site is basically read-only data that can be mostly accurate and they used read-only entity EJBs to create an effective data cache. theserveride.com is the epitomy of a great use case of where entity EJBs can be beneficial.
2) Check out my Why EJB 2.0.ppt presentation that's really more of an entity EJB CMP best practices PPT. It's located at developer.bea.com in the EJB tech track.
You explained how the non-transactional 95% was handled. How was the transactional 5% handled? CMP entity beans? BMP entity beans? With session bean facades? Some other approach? Just curious as to what the "best practices" were in the transactional case for this site.
Is <concurrency-strategy>ReadOnly</concurrency-strategy> a WebLogic feature, or is it supported by other app servers?
The other 95% of the site is basically read-only data that can be mostly accurate and they used read-only entity EJBs to create an effective data cache.
How do the cached Entities get refreshed in the case of a post that updates the list?
Let's suppose the app has a cache of 1000's of Entity EJBs holding the various "threads". Then someone posts a message. This results in the creation and use of a transactional EJB (Entity) (confirm?). The transaction ends. How does the app then refresh the non-tran read-only EJB holding the (previous) state of that post?
How do the cached Entities get refreshed in the case of a post that updates the list?
Two ways with Weblogic 6.1:
- Passive: read-only Entity beans have a time-out value. When it expires, they refresh their data from the database.
- Active: when the data is refreshed, the Entity bean emits an invalidation request to all read-only beans asking them to refresh their data from the database.
- Active: when the data is refreshed, the Entity bean emits an invalidation request to all read-only beans asking them to refresh their data from the database.
Is there any example as to how this is achieved?
Do a search on "Read-Mostly" in BEA's EJB newsgroup.
Tyler, thanks for participating. I do have a question though. You say, regarding theserverside.com, that "The other 95% of the site is basically read-only data that can be mostly accurate and they used read-only entity EJBs to create an effective data cache." I have a big problem with that "mostly accurate" part. It seems that for something like a message board, where it really doesn't that much matter if you have to wait for a half hour (or whatever) for the cached beans to expire, this argument works; for most applications, it doesn't seem to me that it does.
See, now we are getting into generalizations. But, look around at any web-based application -- most of the data is read-mostly data on that site. Even highly transactional sites can design the site so that the transactional portion is minimal.
The point is: transactional design should be a facet of your overall architecture. I would sooner design for scenarios where 90% of my site can make use of non-transactional, mostly accurate read-only beans and the other 10% uses mission-critical, trnsactional beans.
It all comes down to an efficient design.
Tyler, thanks for the article.
I would like your recommendation on our specific case. I am working on a web-based application (Html client) where once the user logs in, he gets a list of companies that he can interact on their behalf (banking system). The list would be requested quite often throughout the system. Therefore, it makes sense to cache it, as opposed to having to retrieve it on every request. We are using Weblogic by the way. Should this data be cashed in the HttpSession (using the session persistence offered by Weblogic) or in a Stateful session bean. The size of data is not really small per user.
Try ReadOnly entity beans.
Unfortunately, I can't use Entity Beans, because I'm reading the data from a Legacy system using some propriatery interface.
There is a need to cache that data. Initially, I wanted to use Stateful session bean, until I read this article.
Why not? As long as the legacy system has a Java API, you can use BMP entity beans to read data from it.
Okay, in other words, use a BMP which would have the "user" as a Primary Key, right?
But then won't it be cheaper/faster to use a Stateful session bean, which typically in my case would have an attribute of type "Collection", and then keep the reference to the bean in the HttpSession for later references. (i.e. what are my advantages by using a BMP?)
Thanks for the help.
Thanks for the reply Tyler.
I still think what you are demonstrating here is more of a performance/convinience issue than the question of whether or not a client holds state. The client still holds a Handle. But that's really just a side note.
The important thing IMO is that beneath the flashing lights and "pyrotechnics", the message of the article is that caution should be taken not to misuse SFSBs (as may be argued about allmost everything). Not that, like some people may have interpreted, SFSBs should be used scarcely and only to take adventage of some obscure features. Good designs that use SFSBs as a fundenmental tool do exist (atleast until someone prooves otherwise). The value of the article is primarily (IMHO) to guide novice users away from inappropriate uses.
The reason I am making a note of this is that when novice users see this thread, they are most likely to get the impression that SFSBs are bad in general. This is what the titles of this discussion and the article indicates, while the content of the article (and explanation by Tyler) indicate otherwise.
I think that a similar discussion can happen over Entity Beans - they can be seriously misused as well. I'm 100% sure that if Tyler to publish an article which starts with
"That's right. You heard it here first. I'm calling Entity EJBs (CMPs and BMPs) the J2EE beasts of burden. I don't care for them. I despise them. I really hate them. I don't dislike what they offer to developers. Rather, I dislike their conniving, misleading, and subtle nature that permits developers to make some of the worst architecture decisions ..."
great many people will enthusiastically agree (and great many will disagree)
I absolutely agree - in fact I think Entity Beans are even more useless! We have started the development of a fairly big J2EE system and after some testing, investigating & reading we have come to the conclusion that they simply don't buy us enough for all the pain we would have had to suffer to develop them PLUS the performance degradation we would have had. Not to mention the extra thousands of dollars app server vendors charge for EJB enabled app servers!
So we settled for good old JSP/Servlets + JDBC within our own framework. And its working like a charm!
I would not write off entity beans. They do solve some problems if used properly, notably scalable concurrency. Also CMP beans require little coding and hence are cheap to write with few bugs. You may find that when you put your Servlet JDBC solution into production it maxes out at a lot less concurrent users than you want. Good luck debugging concurrency problems in hand-coded JDBC.
BTW, to head off a potential thread - Queries are not persistent operations and should not be performed thru entity beans.
Used in the proper context entity beans work quite well. I have run across many architectures where their purpose has been more of a simple storage/retrieval mechanism without regard to transactional scope. Performance of your entity beans can certainly degrade in this scenario. One reasonably straight-forward way to increase performance is to identify where you are not using transactions where you should be (and conversley where you _are_using them and you shouldn't). Entity beans certainly aren't the answer to all of life's problems but they weren't designed to be, either, IMHO.
>Good luck debugging concurrency problems in hand-coded
If their framework is written well (and they're not that difficult to write, I've done it before) then concurrency shouldn't be that big an issue. CMP is also not that useful for very complex data relationships. Without knowing their problem domain and the complexity of their data it's hard to say whether or not CMP would be suitable for their project. And with CMP entity beans, good luck debugging JDBC problems since you didn't write the JDBC code.
Scalability issues can be determined ahead of time with good load testing early on in development. And if you've got good concurrency management built into your application and data layer then you can always just add more servers to your server farm to scale better. ;)
My point was that entity beans have solved the concurrency problem, and in the unlikely event it has not been solved properly I go after the EJB container vendor or switch vendors.
You may know how to write a servlet framework that solves the problem, but as my mother used to say 'Everything is easy when you know how!' My experience is that many (most?) developers have a poor grasp of concurrency issues and transaction management.
Stateless session bean managers over CMP entity beans can handle data complexity (complex data relationships). I.e. CMP can be used for data of any complexity.
It is clearly the intent of the J2EE specification that business domain logic and persistence is implemented as EJBs and servelets be used for presentation and (optionally) state and transaction management. I suspect that many who use servlets for business domain logic and persistence do so, because they do not understand the EJB model and the problems it solves. This indicates to me that their servlet implementations will fail to address these problems, notably concurrency.
My point was that entity beans have solved the concurrency >problem, and in the unlikely event it has not been solved >properly I go after the EJB container vendor or switch >vendors.
Really? Would you elaborate on how you would implement optimistic concurrency using CMP?
>Stateless session bean managers over CMP entity beans can >handle data complexity (complex data relationships). I.e. >CMP can be used for data of any complexity.
If I undestand you correctly, you'll end up hand-coding joins in your SLSB. Good luck with that.
Reply to One Way:
1. An App server can very easily implement optimistic concurrency with CMP2.0. In EJB1.1 CMP this was possible (using JDO-like approach) but far more difficult. Anyway, now it's pretty trivial.
2. You do not have to implement the data access yourself in the scenario of a SFSB representing complex data structures. You can use other beans (possibly CMP entities) for the "building blocks", e.g one entity for each node in a tree. I'd like to note that IMO SFSBs shouldn't "represent" data structures (complex or not). However, they may sometimes have to traverse such data structures and allow the users to query them, in which case they may seem to represent the data structure.
1) Can you elaborate more on how you plan to implement optimistic concurrency with CMP2.0?
2) I never said that you'll have to code data access code yourself. Think about how you are going to work with your "building blocks" to implement a complex relationship. You'll get a collection from one EB and a collection from another EB. Then you'll go through a loop to implement a relationship that you cannot express in EJB-QL. Normally, it's much simpler to do this using a SQL query or sp.
So, my point is that one could try to implement a complex relationship using SLSB facade + EBs but that will lead to poor performance and waste of time/resources.
This is a reasonable article on CMP and optimistic locking
From the article - 'So, I hope you now understand how generic CMP works and interacts with the database. If you use BMP then it changes nothing unless you're very clever with your BMP code (and probably violate the EJB spec). The container calls the ejbLoad and ejbStore methods exactly the same for both BMP and CMP.'
The article says nothing about how one can implement optimistic concurrency with CMP. In fact, I believe it cannot be done unless one adds timestamp/version column as a part of PK, which is not a good idea at all.
This is an extract from the chapter I wrote in the book J2EE in Practice:
The optimistic concurrency mechanisms provided by the
Borland AppServer are only relevant to concurrent transactions. The mechanism is implemented by comparing the state loaded from the database with the state in the database at the time of update. Though very useful, this design falls short when we look at the current way of designing of business processes and user interfaces.
What it doesn’t address is the fact that an entity bean’s state can be displayed to a user using one transaction and updated by the same user in another transaction. During the time between the read and write transaction, another user could have committed an update. The optimistic concurrency
mechanism does not work in this situation, since the state loaded at the start of the write transaction already reflects the update done by another user.
A mechanism is needed to track the versioning of an entity bean’s state across transac-tions. There are a number of ways to approach this, including:
1. Use a stateful session bean to keep a copy of the image sent to the user for editing. When the session bean performs the update, it compares the state of the entity bean with the state it stored in the previous transaction. In the event of conflicts, it throws an exception back to the client.
2. Use a stateless session bean that has two parameters: the state read and the state edited. The comparison process is exactly the same for the stateful session bean. Here the client is required to keep track of the state read in
the first transaction.
3. Similar to the previous technique, a version field in the entity bean can be used to track changes. When executing the update, the client sends the edited state object with the version number initially read. Before the session bean performs the update, the version number in the entity bean is compared with the version read in the first transaction. If the version number is older then the current one, an exception is thrown. The drawback is that the database schema must support this new persistent field.
4. Use a client-demarcated transaction that spans the read, edit, and update steps. This has the potential to hold expensive and precious resources for a considerable amount of time.
Using IIOP and interceptors there is a possibility of introducing a less intrusive solution in terms of design.
The EJB 1.1 specification is not specific about how optmisitic concurrency should be implemented. FWIIW neither is the ANSI SQL92 specification. Hence you can rely on a mechanism implemented by your app server vedor or RDBMS vendor and maybe depending on both in combination. Alternatively, you can implement a portable mechanism using some kind of timestamp or other conflict detecting mechanism. I agreed its not elegant, but you have exactly the same problem implementing a portable RDBMS solution. The article I sent you and William Louth's post describe the same basic mechanism(s). There is no reason you can not use this with CMP.
Well I would like to believe our fw is rather good :), but
time will tell...
In our particular case CMP would have worked - the basics of the fw is that everything is stored as metadata. So HTML is built up dynamically from the metadata, persistece is handled dynamically via the metadata (build up the SQL statements, etc.), etc., etc.
We are using JDBC but with connections from the App Server's connection pool - which I believe would handle the concurrency issue. We have not done any major scalability testing yet, so time will tell. The one potential use for EJB's (I thought) is that we want to cache the metadata, but now that seems to be classified as one of the things NOT to do with EJB's ! :)
The issue I have with Entity Beans is that they seem such finicky, temperamental beasts. Coincidently (although it seems to be more the case than not) our IDE (JB5) doesn't support building EJB's for our Appserver (Oracle 9iAS/Orion). So building an EJB (CMP or BMP) has proved to be a major pain -with a million deployment files that need to be hand generated, JARS that need to be built in a special way, with cryptic error messages that basically point you back to square zero. And after all that (hours if not days of schlep) you have ONE entity bean that does inserts, updates, deletes, and VERY SPECIFIC selects for ONE table. We need a very dynamic select capability i.e. use combinations of the attributes to build a dynamic where clause, etc. What about joins? I know there are patterns out there to help, and while I'm a strong believer of design patterns, it seems to me that most of these patterns add more of the same (overdesign, overweight, overcomplication) on top of the whole EJB thing.
To duplicate that effort (CRUD for one table) in our framework I have to insert 1 row in a table + one row for each attribute. I have scripts that read from the DB metadata and populates our metadata so it happens in minutes if not seconds. What is more, I then also have servlets ready for the front end stuff!
Thanks for some very interesting postings...
Just a quick off-topic note. You may want to try Oracle's JDevdeloper 9i (beta). It can generate all of the required files etc from your beans. It doesn't do any of the EJB 2.0 style descriptors - you'd have to modify the 1.1 versions yourself - but it seems to work otherwise. Of course you have all of the Oracle specific functionality in there as well so it can be overkill if you are not using Oracle (we don't) - its free to download at otn.oracle.com.
"So building an EJB (CMP or BMP) has proved to be a major pain -with a million deployment files that need to be hand generated"
This is less a problem with EJB than it is a problem with your tools. Generating the 1-3 XML deployment descriptors for an EJB should typically be a task that takes very little time, especially with tools like EJBGen or one of the many XML editors that will provide the DTD structure for you visually.
"JARS that need to be built in a special way, with cryptic error messages that basically point you back to square zero"
There's nothing special about an EJB jar vs. a regular JAR, beyond 1-3 XML files being included in your META-INF directory.
"And after all that (hours if not days of schlep) you have ONE entity bean that does inserts, updates, deletes, and VERY SPECIFIC selects for ONE table."
I would really question this approach if you are using BMP. With CMP, this is fine, but BMP's should usually be built as "aggregate" entities that span a significant portion of data, mainly because BMP finder methods are often useless you prime the EJB cache first (and have as much memory as your database does :)
" We need a very dynamic select capability i.e. use combinations of the attributes to build a dynamic where clause, etc. What about joins? I know there are patterns out there to help, and while I'm a strong believer of design patterns, it seems to me that most of these patterns add more of the same (overdesign, overweight, overcomplication) on top of the whole EJB thing. "
EJB is not going to cure your data complexities. EJB solves particularly isolated problems in the realm of deployment and interface-based reusability. If you need to do dynamic queries across multiple entities, life is going to be complex unless you build or purchase a tool to assist you (such as TopLink).
One can have a beef with patterns overcomplicating things, but recognize that at some point, the problem needs to be solved. You can't eliminate complexity, only abstract from it... So either bite the bullet and code the pattern, or purchase a product that already has (and deal with the potentially proprietary ramifications).
Some complex activities are still not understood well enough to provide a unversial standard for them, especially given that any standard would have a lot of baggage & philosophy to bias any such solution in a way that may be rather ineffective...
I'm far from an EJB apologist, but I find a lot of the problems people encounter with EJB are due to using them outside of the context their strengths (reusability, deployability, and encapsulation... maybe others.)
Entity EJBs are good, sometimes. You really need to know when to use them and how to use them. For example, having EJBs calling other EJBs is not a good idea. (for the remote calls expense.)
Stateful session bean are not that bad neither... but do NOT use them :) - :) or use them ONLY for memory cache....
I have to take issue with the following statement
'but if you need to implement a persistent, crash-friendly shopping cart, you need to use entity EJBs.'
The article poses (but doesn't answer) an interesting question of how to recover in-process transactions. To use the shopping cart example. I have a shopping cart that exists thru multiple interactions between client and server. I want an ACID transaction to span the life of the shopping cart (a very likely requirement IMO). I also want to recover the state of the shopping cart after server crash. Clearly, I can not use entity beans (representing the order, items and payment) to do this, as the only way to persist the data is to commit a transaction, which violates my ACID Tx over life of shopping cart requirement above.
I would solve this problem by periodically persisting the internal state of the transation thru a separate persistence mechanism and separate Tx, probably not using entity beans as there is no concurrency requirement. The last step in my ACID shopping cart Tx is to delete the persistent internal state. This activity has to occur where-ever session and transaction state is managed, which may be a session bean.
"I want an ACID transaction to span the life of the shopping cart (a very likely requirement IMO)"
Having any ACID transaction exist across user think time is a bad thing ! Every add, delete and change to the cart should itself be a single ACID transaction. At the end of the checkout process all the transient data from the cart should be removed, and the comfirmed orders should be created, in a single ACID transaction.
You can implement all of this in a variety of ways, using enity beans, or stateless session beans making JDBC calls, or whatever model you prefer.
I think your problem is not separating the orders from the cart items - these are two distinct concepts. An shopping cart item persists until checkout, an order persists from checkout until shipping, and probably beyond for historical tracking. Modeled correctly, these could be EJBs.
I politely disagree with the conclusion of this article, and have a couple of disagreements with Floyd's further comments.
I do think Tyler makes important points, most of which are correct. The conclusion, however, does not follow. Here's my reasoning (top down):
Stateful session beans extend the notion of a "transient working set" aka. conversational state into the realm of reusable components. It may be used to justify poor architecture, but let's not lose sight of the fact that the EJB specification repeatedly refers to Stateful session beans as the "most common" type of bean, and Stateless session beans as "an exceptional" kind of bean. That should give one a hint as to their importance.
Here are my claims, which overlaps some of Tyler':
- SFSB's are fully-synchronized objects (usually one calls an SFSB through a synchronized delegate) so don't have any advantages over alternatives (HttpSession) if a client performs concurrent requests.
- SFSB's have activation/passivation notifications.
- SFSB's can provide a custom interface for storing and querying state beyond a simple key/value pair interface.
- SFSB's can index the data in any way it likes (Trees, Hashes, Bits, etc)
- SFSB's intercept transaction boundaries to perform custom persistence of any in-memory modifications to the transient working set, if necessary.
- SFSB's encapsulate most of the state management "guck" that one doesn't *want* a client to have inside of it.
Those are some clear benefits. Obviously there's some political problems with people misunderstanding SFSB's and then claiming that "EJB sucks", but I would suggest this goes double for entity beans. YMMV.
For web applications, HttpSession is often enough. If you want the above benefits, an SFSB works fine, (and if you want to crash-proof it, my suggestion would be to either intercept tx boundaries with SessionSynchronization and persist the state, or to just go on and use an entity bean).
For non-web clients, web services in particular, SFSB's are clearly effective. Web services are completely dependent on how many people "hook into" your service. Do you *really* want to force your clients to store ALL of their own transient state, particularly when it could be complex? It's a value-add to store conversational state on the server side. It's certainly an engineering tradeoff, but it's not appropriate to write it off just because "stateless scales better".
It all depends on what you're trying to accomplish -- as HttpSession has shown us in the web paradigm, sometimes it really IS better to use a simpler but less scalable approach than to futz with cookies & hidden form fields.
Floyd claims that the semantics of a workflow will change drastically depending on UI technology a client uses. He's correct in that screen flow & GUI feel will drastically change between technologies, but I believe this is stretching the definition of "workflow". If one is automating a business process by routing tasks & documents to people, this usually is independent of GUI. It also makes "workflow" inherently persistent and probably better suited for an entity bean, though one could persist changes to a stateful session bean's graph through the transaction callbacks.
State management is about efficiently managing working sets. It is a value-add to simplify client development and is quite suitable for scenarios where the client is thin and/or must have as simple an interface as possible. Many such scenarios exist and require the trade-off of increased memory requirements on the server.
My feeling is that a lot of the comments against Stateful session beans are more biased to "current implementations" of state management algorithms in EJB servers, which are, well, young. Notwithstanding this unfortunate situation, the use of transient sessions with large working sets has proven to have great utility in simplifying development (examples are virtual memory, object caching systems, in-memory databases, etc.)
'Do you *really* want to force your (web service) clients to store ALL of their own transient state' = YES! Web services are inherently stateless.
As soon as you put state in web services it will be spread all over the place. Impossible to manage! However, the state may be stored in a SFSB intermediary between the client and the web services.
Web services use an inherently stateless protocol; this does not imply that they themselves are inherently stateless.
If Amazon.com exposes book buying as a web service, it's going to keep track of state. How it chooses to store such state (i.e. persist some things for recovery, keep other things transient, such as "The Page You Made"), is an engineering tradeoff.
Let me clarify one thing I said about my Amazon.com example:
"it's going to keep track of state". What I'm basically saying is that there's nothing wrong with a web service offering functionality similar to a shopping cart. Think wishlists, etc. Sometimes it's appropriate to expose something completely stateless like "send me all the ISBN's of the books you want to buy". But I think there's also the possibility that there's going to be a bit of a conversation going on for this kind of transaction, and especially for other more complex domain transactions, especially multi-user transactions like exchanges.
It's a matter what level of development burden that the service provider wants to place on the client developer.
You are correct that web services could be stateful. I was arguing that they should not be stateful, on the principle that session state should in one place (fat client, servlet or SFSB). However, having worked thru an example of web services that are stateful, it does seem to work.
INVENTORY MANAGEMENT service
- reserveinventory(clientid, partno, quantity)
- unreserveinventory(clientid, partno)
- commitreserved inventory(clientid)
The inventory management service maintains the current uncommitted inventory state for the client. Adding new stateful services like Account management(reservefunds, commitfunds, getavailablebalance) doesn't seem to cause problems.
I still think a stateless model is preferrable, but now see how a stateful web services model would work.
I like your arguments Stu. I think it is important to note the "this is bad in practice when..." and "this is bad".
In theory SFSB's make perfect sense. Having a component that can take care of its own state, and a container that can manage it (swapping out when it needs to) is great. This is a lot nicer than having a client holding absolutely everything... more "procedural".
So this really is coming to performance/scalability. Often you will be able to get adaquate performance with SFSBs. I mean, if you *really* want performance, then go back to writing assembly. This is the same for Entity Beans. How nice is it to be able to generate CMP (or even BMP) Entities from a domain model (or database) using tools. You save a lot of time (important) and get a working solution. When you have a working prototype you can profile it and see the bottlenecks. Remember the 80/20 rule, and only tune what NEEDS to be tuned!
This all reminds me of the recent report regarding the large number of companies that wasted money on expensive appservers only to use JSP/Servlets/JDBC. The authors took the view that waste was in the purchase order whereas I see the waste in the development effort. Writing JDBC code is a pain and writing a reliable persistent framework is not going to win over users; they want applications not infrastructure.
I expect that we have at this stage thousands of JSP/Servlet developers writing persistent managers. Probably explains why most JSP/Servlet books always have a chapter on JDBC.
I think the goal of any EJB architect or developer should be to do as little as possible to achieve their objectives. I know this sounds so obvious but would you believe it to be true on most projects. NO.
Maybe this all stems from the fact they most developers suffer from some form of displacement when it comes to moving outside of the technology domain and into the business domain. The comfort factor?
I expect that we have at this stage thousands of JSP/Servlet developers writing persistent managers.
>Probably explains why most JSP/Servlet books always have a
chapter on JDBC.
Speaking of misuses, JSP is probably the most popular and the most commonly misused J2EE technology. Most likely, great proportion of JSP developers you mention implement persistence management right on the JSP pages (after reading the JDBC chapter).
I agree with you Stu, that Tyler is correct in most of his advices, but his conclusion is wrong. SFSB's should not play a minor role. From my experience working in OO application development for 15 years +80% of the classes in an OO design are stateful without being persistent, and that tells me there is a big potential for SFSB's.
However, there is one problem with SFSB's, and that's session bean timeout. A session bean, that has not been used for a certain time may be destroyed (not passivated), and that's why cascading SFSB's may cause dangling references. Many EJB-centric applications is based on a 'petstore like' architecture, where a SFSB acts as the central controller in the MVC pattern, and with the timeout problem in mind it should be the only SFSB ?
Where should client data be placed: HttpSession or SFSB?
From my experience, and if I'm wrong please let me know:
In web apps with JSP/servlet front-ends, you have to use HttpSession to store client data, and SFSB simply does not work. SFSB works well for "rich client" applications, but in web apps, you have a problem: what is the client?. I think the client is the servlet/JSP/bean that calls the EJB, and you cannot use the EJB further.
"Systems that have JSP/servlet front-ends should use HttpSession objects to store session-oriented state on behalf of a client. Applications that manage an HttpSession object and an SFSB for a single client wind up duplicating effort that does not need to be duplicated"
Reading this, seems that both can be used, but after some frustrating tryings I reach the conclussion that only HttpSession can be used. And then, looking at the Pet Store I realise that the famous ShoppingCart SFSB that "contains client data" are pushed into the HttpSession.
SFSB are extremely important, tyler's despise notwithstanding.
First of all Stateful Session beans exist in a managed environment. Imagine storing tons of data in a Servlet Session object. The whole memory starts getting filled up. Contrats this with the EJB container swapping the non-active sessions onto the disk.
As regards shopping carts and persistence of session data, my application is in the first place is in a failover cluster and I replicate my SFSB over them. IT IS HIGHLY UNLIKELY THAT ALL MY DISTRIBUTED MACHINES FAIL in one go. For that matter anything including RDBMS can have a fatal crash.
So considering the managed and failsafe environment, SFSB are very important
Depending on your app server, the HTTP session state is managed in exactly the same way as SFSBs, ie passivation, replication, etc. This is not the issue you make it out to be.
I have been reading discussions and articles on this site for a few months.
Honestly I am starting to think that nobody here believes in the technology they are using.
There are tons of patterns presented and discussed, but no clear explanation of which ones you can use together and which ones you should never mix.
I cannot really believe that both Entity Beans and Stateful Beans are useless. It is like saying that the whole J2EE is useless (which, as a complaint, would make more sense).
If I can use a SSFB to cache data, I see that it works fine and, most important, accomplishes my needs, why shouldn't I?
I do not have the time necessary to wait until all J2EE architects agree and tell me what's the perfect design.
If my opinion is worth anything, I would have to say I hate the Bean concept all together, it seems that Java has switched from Object Oriented to Bean Oriented.
I will adventure to explain the why of what you're observing (nobody believing in this technology). First, a lot of people got caught by the hype surrounding EJB. Most people thought (me include) that EJB was a solution-to-all-problems. But as you delve deep into EJB, and you start to notice it complexities, three things could happen:
1) You are scared away because you lack a solid understanding of most of the concepts, or even a solid understanding of Java. (Most of the people that evangelises the use of a JSP/servlet/JDBC solution in all cases)
2) You screw it because you lack a solid understanding of OOP and OOD, the proposed architecture, the whats and whats-not, etc. (Most of the people that says that EJB sucks, and what happens the fist time to most of us)
3) You build a well designed application, that is scalable, fast and solid as a rock. (I guess no one did this on it's first shot ;) )
So, what you can see is a mixture of frustration and anger for those thing not understood and those lost hours.
Well, on the first shot I built an application that was fast and solid as a rock using Weblogic 5.0 (later 5.1) CMP EJBs. It wasn't scalable though. Frankly, it completely saturated the database server with about three concurrent users.
Live and learn. I still use entity EJBs, and I even use CMPs for certain tasks. It's a tool. Sometimes it is a bulky tool, sometimes it isn't the easiest to use (by a long shot), but when it fits, I use it.
I have been reading this thread and various responses to it and its very interesting. I would like to know the authors' and other people who are following this thread their thoughts on the following benfits of using SFSBs:
1. Managing numerous state related objects. If the application requires that the Session store hundreds of objects, wouldn't it be easier to use SFSB to manage it all. The objects that I want to put in my "shopping cart" are actually dependent on each other, so I am using an SFSB to have more control on the objects that I want to put in the cart.
2. I completely agree with William Louth; sometimes the ease of development with SFSB to store state more than compensates the benefit you might get putting session in HTTPSession. We have a centralized place for managing multiple user requests and if failover is required, It is relatively easier to persist using some kind of asynchronous messaging.
I'm a new comer of j2ee, and I can't understand why it'll be deadlock to use stateful session beans to access database only for read.
Trouble with this is that HTTPSession doesn't scale. Anyone who has experience with ASP can tell you that Session variables will slow your system down...SFSB are meant to alleviate some of these difficulties with neat pooling and passivation behind the scenes. So now we are back where we started.
But, if you read the article carefully, HttpSession objects do scale -- app server vendors are allowed to implement activation / passivation schemes on HttpSession objects. WebLogic works that way. Given this behavior, as the article points out, a slick HttpSession implementation is just as scalable as a SFSB implementation.
It's this big assumption that leads me to the points that I make throughout the rest of the article.
Hmm, maybe I'm missing somthing but... There seems to be nothing in this article that says why HttpSession objects are better than SFSB. There is a reference to how HttpSession *might* be as scalable as SFSB ie your vendor *might* have implemented cache management, hardly portable.
One of the main things I dislike about HttpSession is its crude name value pair interface. In most applications I have seen this mechanism rapidly gets abused and becomes a dump all global data store. A rich object interface seems a much cleaner approach.
SFSB's can be used by a non web application, OK you say not that often this is needed, but why write code in a way that isn'r re-usable when there are no obvious benefits.
SFSB - Tranasactional, rich objects, cache managed, re-usable with non web apps
HttpSession - Not transactional, crude key-value pair interface, *possibly* cache managed, not re-usable for non-web apps
So just remnind HttpSession is better because???
A quick note: The state of a SFSB is not necessarily transactional ... you have to do that work.
Great!. Started reading at 4PM on this Friday evening, (6.30PM now)First of all. Tyler, Tyler,.. it would be great if you could use some more good title when you write an article. You are abusing something which many developers (Anyway I am not from Sun or any of this community who are developing this spec but a good user of all these specs in their good terms.) and architects spent their invaluable time and brain on these things. Could you please tell me anything in this world which is perfect enough to use? You in that article after giving such a "horrible title" explained some best practices... Why should u first of all do that? Bcos you need attention from someone by "disgracing those people who put their effort behind it?"....
About SFSB and HttpSession.... I have been reading tons of articles... "Both are good for some situations and bad for some other situations."
"EJBs never suck"... they are good.. they proved it.. and people who say EJB suck, will be using it without any hesitation by yelling against it.
Use if u like, else look for something which u like..
Finally, no offense to anyone, but it would be great if in future we have articles which are encouraging to those who took the pain to develop all these things for us..
Tyler, I was having a good respect for ur articles till i saw this 'heading'