When you deploy an application, JBoss creates a container for each of your beans. This container will be used only for this particular bean. It must be configured according to the type of the bean (CMP Entity Bean, Stateful Session Bean, etc.). Different standard configurations are stored in the standardjboss.xml file. You may provide additional custom configurations in the jboss.xml file for your application.
JBoss currently provides a standard configuration for each type of bean. These configurations are stored in the standardjboss.xml file. There are currently 8 standard configurations. If you don't provide anything else (as we advise you to do, at least at the beginning), JBoss will automatically choose the right standard configuration for your container. The available configurations are the following:
The first four ones are used if you run JBoss with a jdk1.3 JVM. The four last ones are used if you run JBoss with a jdk1.2.2 JVM.
If you run JBoss on a jdk1.3 JVM, but your clients use jdk1.2.2, the standard configuration won't work (the protocols are not backward compatible). In this case, you have to force JBoss to use the corresponding jdk1.2.2 configuration. You do that by providing a jboss.xml file. This file must be in the META-INF directory of your jar file, along with ejb-jar.xml. In the section for your bean, simply add a <configuration-name> tag. Your xml files will look like this (note that the <ejb-name> tags in the 2 xml files must match) ejb-jar.xml:
<ejb-jar> <enterprise-beans> <session> <ejb-name>Bean A</ejb-name> <home>AHome</home> <remote>A</remote> <ejb-class>ABean</ejb-class> <session-type>Stateful</session-type> <transaction-type>Container</transaction-type> </ejb-ref> </session> </enterprise-beans> ... </ejb-jar>
<jboss> <enterprise-beans> <session> <ejb-name>Bean A</ejb-name> <configuration-name>jdk1.2.2 Stateful SessionBean<configuration-name> </session> <enterprise-beans> </jboss>
You may want to provide your own advanced configuration. For example, you may want to increase the size of your pool, or use a different instance cache. To do this, you must define your configuration in jboss.xml in the <container-configurations> tag. Then you have to use your new configuration in the bean section of your jboss.xml file. For example, if you want to log calls to your bean, your file will look like this :
<jboss> <enterprise-beans> <session> <ejb-name>Bean A</ejb-name> <configuration-name>Logging Configuration<configuration-name> </session> <enterprise-beans> ... <container-configurations> <container-configuration> <container-name>Logging Configuration</container-name> <call-logging>true</call-logging> <container-invoker>org.jboss.ejb.plugins.jrmp13.server.JRMPContainerInvoker</container-invoker> <instance-cache>org.jboss.ejb.plugins.StatefulSessionInstanceCache</instance-cache> <persistence-manager>org.jboss.ejb.plugins.StatefulSessionFilePersistenceManager</persistence-manager> <transaction-manager>org.jboss.tm.TxManager</transaction-manager> <container-invoker-conf> <Optimized>False</Optimized> </container-invoker-conf> </container-configuration> </container-configurations> ... </jboss>
These are the different things you can customize in a <container-configuration> tag in jboss.xml. See the jboss.xml DTD for more details:
<instance-pool> the instance pool is a set (a "pool") of free (ie not currently associated to a context) instances of the bean. When an instance of the bean is no longer used, it is thrown back to the pool. This is not used for Stateful Session Beans, since the instances are not reusable.
<instance-cache> the cache contains the instances of a bean which are currently associated to a context. If it grows too big, the cache may decide to passivate some of the instances. This is not used for Stateless Session Beans, since these are directly reusable after a call.
<persistence-manager> the persistence manager is in charge of storing permanent information in the instance of a bean. For BMP Entities, it will merely transmit orders to the bean; for Stateful Sessions and CMP Entities, it has to save the state of the bean. This is not used for Stateless Session Beans, since they don't have a state to save.
There are several elements which can nest within container-invoker-conf, one of which is <Optimized>. This controls the behavior of bean method calls within the Java VM in which jboss is running. If the value of Optimized is "false" then the container will behave per the EJB spec and all objects passed into and out of bean remote methods will be marshalled over RMI regardless of whether the client is running remotely or in the same VM as jboss.
If the value of Optimized is "true" then objects passed between bean methods and clients in the jboss java VM will be passed by reference rather than by value. This is much more efficient (and can result in substantial performance improvements) but can result in unexpected behavior. For example, if a bean has a member object and returns that object from a get() method then the EJB-specified behavior is to make a copy of that object which is returned over RMI to the caller. Therefore if the caller modifies the returned object in any way she will modify the copy of the object. If Optimized is "true" then the caller will modify the original object per se, rather than a copy.
Option A: The container caches the beans state between transactions. This options assumes that the bean/container is the only one accessing the persistent data. Therefore the container synchronizes the memory state from the persistent storage only (via ejbLoad) when absolutely neccessary (when the state isn't cached yet), that is before the first business method executes on a found bean or after the bean is passivated and reactivated to serve another business method. This behaviour is regardless of wether the business method executes inside or outside a transaction.
Option B: The container caches the bean between transactions. However, unlike option A the container does not have exclusive access to the persistent storage. Therefore, the container will synchronize the memory state (via ejbLoad) at the beginning of each transaction. Thus business methods executing in a transaction context don't see much benefit from the container caching the bean, whereas business methods executing outside a transaction context (transaction attributes Never, NotSupported or Supports) access the cached (and invalid) state of the bean.
Option C: The container does not cache bean instances and instances memory state is synchronized on every transaction start (via ejbLoad). For business methods executing outside a transaction the synchronization is done too, but as the ejbLoad executes in the same transaction context as the triggering business method, the state must still be considered invalid and might already have changed in the persistent storage when the business method executes.
Option D: This is a JBoss specific feature available in the actual version from CVS only. It enables a lazy read schema, where the beans state is cached between transactions as with option A, but resynchronized from the persistent storage from time to time (via ejbLoad). The default time between resynchronizations is 30 seconds but you may configure the time (in seconds) with <optiond-refresh-rate>42</optiond-refresh-rate>.
With all four commit options the container must synchronize the bean instances cached state with the persistent storage (via ejbStore) at the end of each transaction (just before a commit is done) to be sure the whole transactions state is consistently persistet. As of the EJB specification there is no safe way for the container to decide, if the beans state actually has changed since transaction start, so ejbStore is called, even when all access to the beans business methods was read only. Note, however, that JBoss supports an optional method public boolean isModified() in the beans implementation. If this method returns false, the call to ejbStore is skipped at commit time.
A final note to executing business methods outside of a transaction context: when reading the beans state you always must consider the result as invalid and usable for rough display purposes only, i.e. to fill in a large table, having benefit from bean caching (with options A, B and D) and avoiding unneccessary concurrency; even with commit option A, though you get the actual state initially, another concurrent client might change the beans state a microsecond after your read. Never write access a bean outside a transaction context believing ejbStore will be called for synchronization, it typically will not (though somtimes it might, when the container passivates the bean) be called. Read the EJB specification 1.1 sections 18.104.22.168 and 11.6.3 carefully, if you plan to use the transaction attributes Never, NotSupported or Supports.
To safely write a bean depending on it's current state ever (re)read and write the bean within one and the same transaction context.
JBoss currently provides the possibility to choose the cache configuration for each container configuration. You may want to define your own cache settings, and to do so you must specify them in jboss.xml under the <instance-cache> tag and subtags. Currently 2 cache algorithms have been implemented: a no passivation cache algorithm (so that all the bean are kept in memory, unless the bean is an entity bean and you specified for it commit option C), and a least recently used (LRU) cache algorithm (so that bean less frequently used are passivated to save server resources).
Let's see how to configure both caches. The examples below are about entity beans, but the cache settings applies as well for stateful session beans.For the no passivation cache, jboss.xml will look like this:
<jboss> <enterprise-beans> <entity> <ejb-name>Bean A</ejb-name> <configuration-name>No Passivation Configuration<configuration-name> </entity> <enterprise-beans> ... <container-configurations> <container-configuration> <container-name>No Passivation Configuration</container-name> ... <instance-cache>org.jboss.ejb.plugins.EntitySessionInstanceCache</instance-cache> <container-cache-conf> <cache-policy>org.jboss.ejb.plugins.NoPassivationCachePolicy</cache-policy> </container-cache-conf> ... </container-configuration> </container-configurations> ... </jboss>
No further settings are available for the no passivation cache. For the LRU cache, jboss.xml will look like this:
<jboss> <enterprise-beans> <entity> <ejb-name>Bean A</ejb-name> <configuration-name>LRU Configuration<configuration-name> </entity> <enterprise-beans> ... <container-configurations> <container-configuration> <container-name>LRU Configuration</container-name> ... <instance-cache>org.jboss.ejb.plugins.EntitySessionInstanceCache</instance-cache> <container-cache-conf> <cache-policy>org.jboss.ejb.plugins.LRUEnterpriseContextCachePolicy</cache-policy> <cache-policy-conf> <min-capacity>5</min-capacity> <max-capacity>200</max-capacity> <overager-period>300</overager-period> <max-bean-age>600</max-bean-age> <resizer-period>400</resizer-period> <max-cache-miss-period>60</max-cache-miss-period> <min-cache-miss-period>1</min-cache-miss-period> <cache-load-factor>0.75</cache-load-factor> </cache-policy-conf> </container-cache-conf> ... </container-configuration> </container-configurations> ... </jboss>
<cache-policy-conf> and its subtags are optional, so you can specify none, few or all of them. <min-capacity> specifies the minimum capacity of the cache. The cache can be empty, but will have room for at least 5 beans (in the above case); this value cannot be less than 2; the resizer (see below) will shrink the cache capacity down to but not less than this value.
<max-capacity> specifies the maximum capacity of the cache. The cache can be empty, but will have room for at most 200 beans (in the above case); this value cannot be less than the minimum capacity; the resizer (see below) will enlarge the cache capacity up to but not more than this value.
<overager-period> specifies the period of the overager, that is a periodic task that runs (in the above case) every 300 seconds. Purpose of this periodic task is to see if in the cache there are very old beans, and to passivate them. The age at which a bean is considered too old is also configurable (see below). While the period of this task is 300 seconds, the first run happens at a random time between 0 and 300 seconds. To disable the overager set the period to 0.
<max-bean-age> specifies the max age a bean can have before being passivated by the overager (in this case 600 seconds). The tag <resizer-period> specifies the period of the resizer, that is a periodic task that runs (in the above case) every 400 seconds. Purpose of this periodic task is to shrink / enlarge the cache capacity upon 3 other parameters (see below). While the period of this task is 400 seconds, the first run happens at a random time between 0 and 400 seconds. To disable the resizer set the period to 0.
<max-cache-miss-period>,<min-cache-miss-period> and <cache-load-factor> control the resizer in this way: the number of cache misses is internally recorded. When the resizer runs, it sees what is the cache miss rate from the last time it ran. If there is more than (in the above case) one cache miss every 1 second (min-cache-miss-period) then the resizer tries to enlarge the cache; if there is less than (in this case) one cache miss every 60 seconds (max-cache-miss-period) then the resizer tries to shrink the cache. How much is the cache enlarged / shrinked ? Here is where the load-factor comes in the picture. When the resizer shrinks, it tries to shrink the cache so that (in this case) the ratio number of beans / cache capacity is 0.75; when the resizer enlarges, it tries to enlarge the cache by a factor 1 / 0.75 == 1.333 (in the above case) plus a correction calculated from the cache miss rate (so that the more cache miss rate you have, the more the cache is enlarged, starting from at least 1.333; so if you really have a lot of cache misses, the resizer may decide to enlarge the cache of a factor 2.0 instead of 1.333 - if there is room for that).