Wow, that was quick. I'm quite shocked actually :)
You've definitely got the big picture.
On May 28, 2010, at 6:56 AM, Thiago Veronezi wrote:
> Hi David,
> thanks for the directions. I think thats a good task for me to have a global
> view of the system. I think its becoming more clear how to implement the
> fix. Please, verify it for me...
>
> ************************************
> add new class org.apache.openejb.jee.StatefulTimeoutConfig
>
> class StatefulTimeoutConfig {
> @XmlEnumValue("timeout") TIMEOUT,
> @XmlEnumValue("unit") UNIT;
> }
Note that @StatefulTimeout is a different annotation then @AccessTimeout -- see
spec for details. It has the exact xml schema details too.
We will have to support both, so feel free to add that JAXB item while your in
the code. Perhaps a "Timeout" class that could be reused by both.
Note also that <access-timeout> is a list as it's possible to specify the
access timeout for each individual method. I'm totally fine if we want to
ignore that in the in the first patch and come back and do it in a second
revision. It's already a lot to chew on and "per method" metadata is tougher
to pull through the system.
On naming conventions, we typically go with the xml element name with no added
suffix.
> ************************************
> TransactionType
>
> Add a new property (say statefulTimeout) to
> the org.apache.openejb.jee.SessionBean class (below)
>
> @XmlElement(name = "stateful-timeout")
> protected StatefulTimeoutConfig statefulTimeout;
>
> ************************************
> Add the new entry (on bold - same org.apache.openejb.jee.SessionBean class)
> to the "session-beanType" annotation
>
> @XmlType(name = "session-beanType", propOrder = {
> "descriptions",
> "displayNames",
> "icon",
> "ejbName",
> "mappedName",
> "home",
> "remote",
> "localHome",
> "local",
> "businessLocal",
> "businessRemote",
> "localBean",
> "serviceEndpoint",
> "ejbClass",
> "sessionType",
> "loadOnStartup",
> "timeoutMethod",
> "initMethod",
> "removeMethod",
> "transactionType",
> "concurrencyType",
> "aroundInvoke",
> "envEntry",
> "ejbRef",
> "ejbLocalRef",
> "serviceRef",
> "resourceRef",
> "resourceEnvRef",
> "messageDestinationRef",
> "persistenceContextRef",
> "persistenceUnitRef",
> "postConstruct",
> "preDestroy",
> "postActivate",
> "prePassivate",
> "securityRoleRef",
> "securityIdentity",
> "dependsOn",
> *"statefulTimeout"*
> })
Exactly. Ditto for "acccessTimeout".
> ************************************
> Create a new Class...
> class AccessTimeoutValue {
> long time;
> TimeUnit unit;
> }
>
> ************************************
> add new property to org.apache.openejb.core.CoreDeploymentInfo class
>
> private AccessTimeoutValue accessTimeoutValue;
>
> AccessTimeoutValue getAccessTimeoutValue() {
> return this.accessTimeoutValue;
> }
>
> void setAccessTimeoutValue(AccessTimeoutValue accessTimeoutValue) {
> this.accessTimeoutValue = accessTimeoutValue;
> }
For the CoreDeploymentInfo class we can use an existing class called
org.apache.openejb.util.Duration. It does some other fancy stuff, but
basically it's a long/TimeUnit tuple.
As noted above, feel free to ignore the fact that AccessTimeout can be done on
a per method basis. Eventually we'll need some map here, but it's fine to
ignore because I have some fancy ideas for what we should use as the default
when they haven't specified the AccessTimeout for a specific method.
Maybe better to get something basic done and checked in. I suspect the code
will be changing kind of fast with all the other EJB 3.1 work we have going on
and holding big changes can be hard. In fact, feel free to submit patches for
individual little parts of this while chunk of work. I tried to break it up
into sort of logical "bites" in our road map:
http://openejb.apache.org/ejb-31-roadmap.html
Feel free to attach patches to those individual jiras.
> ************************************
> Class org.apache.openejb.assembler.classic.EnterpriseBeanInfo
>
> add new property
> public AccessTimeoutValue accessTimeout;
>
> ************************************
>
> Class org.apache.openejb.config.EjbJarInfoBuilder (line 564)
>
> bean.accessTimeout = new AccessTimeoutValue(
> Long.valueof(s.geStatefulTimeout().TIMEOUT),
> Long.valueof(s.geStatefulTimeout().UNIT));
To match the Timeout class of the jaxb tree, we can make a TimeoutInfo class.
See OpenEjbConfigurationValidationTest for the rules we have in place.
> ************************************
> Class org.apache.openejb.core.stateful.StatefulContainer.
[...]
> Use...
> synchronized (instance) {
> *final AccessTimeoutValue accessTimeout =
> instance.deploymentInfo.getAccessTimeoutValue();*
>
> Lock currLock = instance.getLock();
> final boolean lockAcquired;
> if(accessTimeout == null) {
> // returns immediately true if the lock is available
> lockAcquired = currLock.tryLock();
> } else {
> // AccessTimeout annotation found.
> // Trying to get the lock within the specified period.
> try {
> lockAcquired = currLock.tryLock(accessTimeout.value(),
> accessTimeout.unit());
> } catch (InterruptedException e) {
> throw new ApplicationException("Unable to get lock.", e);
> }
> }
> // Did we acquire the lock to the current execution?
> if (!lockAcquired) {
> throw new ApplicationException(
> new ConcurrentAccessTimeoutException("Unable to get lock."));
> }
This is the part that is a little tricky. Basically all of that synchronized
block has to get rewritten. The "gotcha" is that if someone is waiting
(tryAquire(1, MINUTE)) inside a synchronized block, then all other threads
trying to access that instance will also have to wait just to enter the
synchronized block and get their chance to call "tryAquire", which if course
involves more waiting.
I'm not entirely sure we need the synchronized block anymore. At best we need
it after the lock aquire. That of course makes the "tryLock()" call already
happening a bit strange.
Will probably take some experimentation/testing to get it nailed down.
-David