Source Code Cross Referenced for EntityInstanceManager.java in  » J2EE » openejb3 » org » apache » openejb » core » entity » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » J2EE » openejb3 » org.apache.openejb.core.entity 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /**
002:         * Licensed to the Apache Software Foundation (ASF) under one or more
003:         * contributor license agreements.  See the NOTICE file distributed with
004:         * this work for additional information regarding copyright ownership.
005:         * The ASF licenses this file to You under the Apache License, Version 2.0
006:         * (the "License"); you may not use this file except in compliance with
007:         * the License.  You may obtain a copy of the License at
008:         *
009:         *     http://www.apache.org/licenses/LICENSE-2.0
010:         *
011:         * Unless required by applicable law or agreed to in writing, software
012:         * distributed under the License is distributed on an "AS IS" BASIS,
013:         * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014:         * See the License for the specific language governing permissions and
015:         * limitations under the License.
016:         */package org.apache.openejb.core.entity;
017:
018:        import org.apache.openejb.ApplicationException;
019:        import org.apache.openejb.OpenEJBException;
020:        import org.apache.openejb.SystemException;
021:        import org.apache.openejb.InvalidateReferenceException;
022:        import org.apache.openejb.DeploymentInfo;
023:        import org.apache.openejb.spi.SecurityService;
024:        import org.apache.openejb.core.BaseContext;
025:        import org.apache.openejb.core.CoreDeploymentInfo;
026:        import org.apache.openejb.core.Operation;
027:        import org.apache.openejb.core.ThreadContext;
028:        import org.apache.openejb.core.NoSuchObjectException;
029:        import org.apache.openejb.core.transaction.TransactionRolledbackException;
030:        import org.apache.openejb.util.LinkedListStack;
031:        import org.apache.openejb.util.LogCategory;
032:        import org.apache.openejb.util.Logger;
033:        import org.apache.openejb.util.SafeToolkit;
034:        import org.apache.openejb.util.Stack;
035:
036:        import javax.ejb.EntityBean;
037:        import javax.ejb.NoSuchEntityException;
038:        import javax.transaction.Transaction;
039:        import javax.transaction.TransactionManager;
040:        import javax.transaction.Synchronization;
041:        import javax.transaction.RollbackException;
042:        import java.util.HashMap;
043:        import java.util.Hashtable;
044:        import java.util.Map;
045:        import java.rmi.RemoteException;
046:
047:        public class EntityInstanceManager {
048:
049:            /* The default size of the bean pools. Every bean class gets its own pool of this size */
050:            protected int poolsize = 0;
051:            /* The container that owns this InstanceManager. Its needed to use the invoke() method
052:               in the obtainInstance( ), which is needed for transactionally safe invokation.
053:             */
054:            protected EntityContainer container;
055:            /*
056:             * Every entity that is registered with a transaciton is kept in this pool until the tx
057:             * completes.  The pool contains SyncronizationWrappers (each holding a reference) keyed
058:             * by using an instance of the inner Key class. The Key class is a compound key composed
059:             * of the tx, deployment, and primary key identifiers.
060:             */
061:            protected Hashtable<Object, SyncronizationWrapper> txReadyPool = new Hashtable<Object, SyncronizationWrapper>();
062:            /*
063:             * contains a collection of LinkListStacks indexed by deployment id. Each indexed stack
064:             * represents the method ready pool of for that class.
065:             */
066:            protected Map<Object, LinkedListStack> poolMap = null;
067:
068:            public Logger logger = Logger.getInstance(LogCategory.OPENEJB,
069:                    "org.apache.openejb.util.resources");
070:
071:            protected SafeToolkit toolkit = SafeToolkit
072:                    .getToolkit("EntityInstanceManager");
073:            private TransactionManager transactionManager;
074:            private SecurityService securityService;
075:
076:            public EntityInstanceManager(EntityContainer container,
077:                    TransactionManager transactionManager,
078:                    SecurityService securityService, int poolSize) {
079:                this .transactionManager = transactionManager;
080:                this .securityService = securityService;
081:                this .poolsize = poolSize;
082:                this .container = container;
083:                poolMap = new HashMap<Object, LinkedListStack>();// put size in later
084:
085:                DeploymentInfo[] deploymentInfos = this .container.deployments();
086:                for (int i = 0; i < deploymentInfos.length; i++) {
087:                    DeploymentInfo deploymentInfo = deploymentInfos[i];
088:                    deploy(deploymentInfo);
089:                }
090:            }
091:
092:            public void deploy(DeploymentInfo deploymentInfo) {
093:                poolMap.put(deploymentInfo.getDeploymentID(),
094:                        new LinkedListStack(poolsize / 2));
095:            }
096:
097:            public void undeploy(DeploymentInfo deploymentInfo) {
098:                poolMap.remove(deploymentInfo.getDeploymentID());
099:            }
100:
101:            public EntityBean obtainInstance(ThreadContext callContext)
102:                    throws OpenEJBException {
103:                Transaction currentTx;
104:                try {
105:                    currentTx = getTransactionManager().getTransaction();
106:                } catch (javax.transaction.SystemException se) {
107:                    logger.error(
108:                            "Transaction Manager getTransaction() failed.", se);
109:                    throw new SystemException("TransactionManager failure", se);
110:                }
111:
112:                Object primaryKey = callContext.getPrimaryKey();// null if its a servicing a home methods (create, find, ejbHome)
113:                if (currentTx != null && primaryKey != null) {// primkey is null if create operation is called
114:                    CoreDeploymentInfo deploymentInfo = callContext
115:                            .getDeploymentInfo();
116:                    Key key = new Key(currentTx, deploymentInfo
117:                            .getDeploymentID(), primaryKey);
118:                    SyncronizationWrapper wrapper = txReadyPool.get(key);
119:
120:                    if (wrapper != null) {// if true, the requested bean instance is already enrolled in a transaction
121:
122:                        if (!wrapper.isAssociated()) {// is NOT associated
123:                            /*
124:                             * If the bean identity was removed (via ejbRemove()) within the same transaction,
125:                             * then it's SynchronizationWrapper will be in the txReady pool but marked as disassociated.
126:                             * This allows us to prevent a condition where the caller removes the bean and then attempts to
127:                             * call a business method on that bean within the same transaction.  After a bean is removed any
128:                             * subsequent invocations on that bean with the same transaction should throw a NoSuchEntityException.
129:                             * its likely that the application server would have already made the reference invalid, but this bit of
130:                             * code is an extra precaution.
131:                             */
132:                            throw new InvalidateReferenceException(
133:                                    new NoSuchObjectException(
134:                                            "Entity not found: " + primaryKey));
135:                        } else if (callContext.getCurrentOperation() == Operation.REMOVE) {
136:                            /*
137:                             *  To avoid calling ejbStore( ) on a bean that after its removed, we can not delegate
138:                             *  the wrapper is marked as disassociated from the transaction to avoid processing the
139:                             *  beforeCompletion( ) method on the SynchronizationWrapper object.
140:                             */
141:                            wrapper.disassociate();
142:                        }
143:
144:                        if (wrapper.isAvailable()
145:                                || wrapper.primaryKey.equals(primaryKey)) {
146:                            return wrapper.getEntityBean();
147:                        } else {
148:
149:                            // If the bean is declared as reentrant then the instance may be accessed
150:                            // by more then one thread at a time.  This is one of the reasons that reentrancy
151:                            // is bad. In this case beans must be programmed to be multi threaded. The other reason
152:                            // reentrancy is bad has to do with transaction isolation. Multiple instances writing to
153:                            // the same database records will inevitably cancel out previous writes within the same tx.
154:                            //
155:                            // In the future we may change this to return a new instance of the bean and to
156:                            // link it and its wrapper to the original wrapper, but for now we choose this strategy because
157:                            // its simpler to implement.
158:                            return wrapper.getEntityBean();
159:                        }
160:                    } else {
161:                        /*
162:                         * If no synchronized wrapper for the key exists
163:                         * Then the bean entity is being access by this transaction for the first time,
164:                         * so it needs to be enrolled in the transaction.
165:                         */
166:                        EntityBean bean = getPooledInstance(callContext);
167:                        wrapper = new SyncronizationWrapper(callContext
168:                                .getDeploymentInfo(), primaryKey, bean, false,
169:                                key);
170:
171:                        if (callContext.getCurrentOperation() == Operation.REMOVE) {
172:                            /*
173:                             *  To avoid calling ejbStore( ) on a bean that after its removed, we can not delegate
174:                             *  the wrapper is marked as disassociated from the transaction to avoid processing the
175:                             *  beforeCompletion( ) method on the SynchronizationWrapper object.
176:                             *
177:                             *  We have to still use a wrapper so we can detect when a business method is called after
178:                             *  a ejbRemove() and act to prevent it from being processed.
179:                             */
180:                            wrapper.disassociate();
181:                        }
182:
183:                        try {
184:                            currentTx.registerSynchronization(wrapper);
185:                        } catch (javax.transaction.SystemException e) {
186:                            logger
187:                                    .error(
188:                                            "Transaction Manager registerSynchronization() failed.",
189:                                            e);
190:                            throw new SystemException(e);
191:                        } catch (RollbackException e) {
192:                            throw new ApplicationException(
193:                                    new TransactionRolledbackException(e));
194:                        }
195:                        loadingBean(bean, callContext);
196:                        Operation orginalOperation = callContext
197:                                .getCurrentOperation();
198:                        callContext.setCurrentOperation(Operation.LOAD);
199:                        try {
200:                            bean.ejbLoad();
201:                        } catch (NoSuchEntityException e) {
202:                            throw new InvalidateReferenceException(
203:                                    new NoSuchObjectException(
204:                                            "Entity not found: " + primaryKey)
205:                                            .initCause(e));
206:                        } catch (Exception e) {
207:                            logger.error(
208:                                    "Exception encountered during ejbLoad():",
209:                                    e);
210:
211:                            throw new OpenEJBException(e);
212:                        } finally {
213:                            callContext.setCurrentOperation(orginalOperation);
214:                            callContext.setCurrentAllowedStates(EntityContext
215:                                    .getStates());
216:                        }
217:                        txReadyPool.put(key, wrapper);
218:
219:                        return bean;
220:                    }
221:                } else {
222:                    // If no transaction is associated with the thread or if its a create, find or home method
223:                    // (primaryKey == null), then no synchronized wrapper is needed. if bean instance is used
224:                    // for a create method then a syncrhonziation wrapper may be assigned when the bean is
225:                    // returned to the pool -- depending on if the tx is a client initiated or container initiated.
226:                    return getPooledInstance(callContext);
227:                }
228:            }
229:
230:            protected void loadingBean(EntityBean bean,
231:                    ThreadContext callContext) throws OpenEJBException {
232:            }
233:
234:            protected void reusingBean(EntityBean bean,
235:                    ThreadContext callContext) throws OpenEJBException {
236:            }
237:
238:            protected EntityBean getPooledInstance(ThreadContext callContext)
239:                    throws OpenEJBException {
240:                CoreDeploymentInfo deploymentInfo = callContext
241:                        .getDeploymentInfo();
242:                Stack methodReadyPool = poolMap.get(deploymentInfo
243:                        .getDeploymentID());
244:                if (methodReadyPool == null)
245:                    throw new SystemException("Invalid deployment id "
246:                            + deploymentInfo.getDeploymentID()
247:                            + " for this container");
248:
249:                EntityBean bean = (EntityBean) methodReadyPool.pop();
250:                if (bean == null) {
251:                    try {
252:                        bean = (EntityBean) deploymentInfo.getBeanClass()
253:                                .newInstance();
254:                    } catch (Exception e) {
255:                        logger.error("Bean instantiation failed for class "
256:                                + deploymentInfo.getBeanClass(), e);
257:                        throw new SystemException(e);
258:                    }
259:
260:                    Operation currentOp = callContext.getCurrentOperation();
261:                    callContext.setCurrentOperation(Operation.SET_CONTEXT);
262:                    BaseContext.State[] originalStates = callContext
263:                            .setCurrentAllowedStates(EntityContext.getStates());
264:
265:                    try {
266:                        /*
267:                         * setEntityContext executes in an unspecified transactional context. In this case we choose to
268:                         * allow it to have what every transaction context is current. Better then suspending it
269:                         * unnecessarily.
270:                         *
271:                         * We also chose not to invoke EntityContainer.invoke( ) method, which duplicate the exception handling
272:                         * logic but also attempt to manage the begining and end of a transaction. It its a container managed transaciton
273:                         * we don't want the TransactionScopeHandler commiting the transaction in afterInvoke() which is what it would attempt
274:                         * to do.
275:                         */
276:                        bean.setEntityContext(createEntityContext());
277:                    } catch (Exception e) {
278:                        /*
279:                         * The EJB 1.1 specification does not specify how exceptions thrown by setEntityContext impact the
280:                         * transaction, if there is one.  In this case we choose the least disruptive operation, throwing an
281:                         * application exception and NOT automatically marking the transaciton for rollback.
282:                         */
283:                        logger.error("Bean callback method failed ", e);
284:                        throw new ApplicationException(e);
285:                    } finally {
286:                        callContext.setCurrentOperation(currentOp);
287:                        callContext.setCurrentAllowedStates(originalStates);
288:                    }
289:                } else {
290:                    reusingBean(bean, callContext);
291:                }
292:
293:                if ((callContext.getCurrentOperation() == Operation.BUSINESS)
294:                        || (callContext.getCurrentOperation() == Operation.REMOVE)) {
295:                    /*
296:                     * When a bean is retrieved from the bean pool to service a client's business method request it must be
297:                     * notified that its about to enter service by invoking its ejbActivate( ) method. A bean instance
298:                     * does not have its ejbActivate() invoked when:
299:                     * 1. Its being retreived to service an ejbCreate()/ejbPostCreate().
300:                     * 2. Its being retrieved to service an ejbFind method.
301:                     * 3. Its being retrieved to service an ejbRemove() method.
302:                     * See section 9.1.4 of the EJB 1.1 specification.
303:                     */
304:                    Operation currentOp = callContext.getCurrentOperation();
305:
306:                    callContext.setCurrentOperation(Operation.ACTIVATE);
307:                    BaseContext.State[] originalStates = callContext
308:                            .setCurrentAllowedStates(EntityContext.getStates());
309:                    try {
310:                        /*
311:                        In the event of an exception, OpenEJB is required to log the exception, evict the instance,
312:                        and mark the transaction for rollback.  If there is a transaction to rollback, then the a
313:                        javax.transaction.TransactionRolledbackException must be throw to the client.
314:                        See EJB 1.1 specification, section 12.3.2
315:                         */
316:                        bean.ejbActivate();
317:                    } catch (Throwable e) {
318:                        logger
319:                                .error(
320:                                        "Encountered exception during call to ejbActivate()",
321:                                        e);
322:                        try {
323:                            Transaction tx = getTransactionManager()
324:                                    .getTransaction();
325:                            if (tx != null) {
326:                                tx.setRollbackOnly();
327:                                throw new ApplicationException(
328:                                        new TransactionRolledbackException(
329:                                                "Reflection exception thrown while attempting to call ejbActivate() on the instance",
330:                                                e));
331:                            }
332:                        } catch (javax.transaction.SystemException se) {
333:                            logger
334:                                    .error(
335:                                            "Transaction Manager getTransaction() failed.",
336:                                            se);
337:                            throw new SystemException(se);
338:                        }
339:                        throw new ApplicationException(
340:                                new RemoteException(
341:                                        "Exception thrown while attempting to call ejbActivate() on the instance. Exception message = "
342:                                                + e.getMessage(), e));
343:                    } finally {
344:                        callContext.setCurrentOperation(currentOp);
345:                        callContext.setCurrentAllowedStates(originalStates);
346:                    }
347:
348:                }
349:                return bean;
350:            }
351:
352:            private EntityContext createEntityContext() {
353:                return new EntityContext(transactionManager, securityService);
354:            }
355:
356:            public void poolInstance(ThreadContext callContext,
357:                    EntityBean bean, Object primaryKey) throws OpenEJBException {
358:                if (bean == null) {
359:                    return;
360:                }
361:                Transaction currentTx = null;
362:                try {
363:                    currentTx = getTransactionManager().getTransaction();
364:                } catch (javax.transaction.SystemException se) {
365:                    logger.error(
366:                            "Transaction Manager getTransaction() failed.", se);
367:                    throw new SystemException("TransactionManager failure", se);
368:                }
369:                if (currentTx != null && primaryKey != null) {// primary key is null for find and home methods
370:                    Key key = new Key(currentTx, callContext
371:                            .getDeploymentInfo().getDeploymentID(), primaryKey);
372:                    SyncronizationWrapper wrapper = txReadyPool.get(key);
373:                    if (wrapper != null) {
374:                        if (callContext.getCurrentOperation() == Operation.REMOVE) {
375:                            /*
376:                             * The bean is being returned to the pool after it has been removed. Its
377:                             * important at this point to mark the bean as disassociated to prevent
378:                             * it's ejbStore method from bean called (see SynchronizationWrapper.beforeCompletion() method)
379:                             * and that subsequent methods can not be invoked on the bean identity (see obtainInstance() method).
380:                             */
381:                            wrapper.disassociate();
382:                            /*
383:                             * If the bean has been removed then the bean instance is no longer needed and can return to the methodReadyPool
384:                             * to service another identity.
385:                             */
386:                            Stack methodReadyPool = poolMap.get(callContext
387:                                    .getDeploymentInfo().getDeploymentID());
388:                            methodReadyPool.push(bean);
389:                        } else {
390:                            if (callContext.getCurrentOperation() == Operation.CREATE) {
391:                                // Bean is being recreated (new-delete-new) so we need to reassociate it
392:                                wrapper.associate();
393:                            }
394:                            wrapper.setEntityBean(bean);
395:                        }
396:                    } else {
397:                        /*
398:                        A wrapper will not exist if the bean is being returned after a create operation.
399:                        In this case the transaction scope is broader then the create method itself; its a client
400:                        initiated transaction, so the bean must be registered with the tranaction and moved to the
401:                        tx ready pool
402:                         */
403:
404:                        wrapper = new SyncronizationWrapper(callContext
405:                                .getDeploymentInfo(), primaryKey, bean, true,
406:                                key);
407:
408:                        try {
409:                            currentTx.registerSynchronization(wrapper);
410:                        } catch (javax.transaction.SystemException se) {
411:                            logger
412:                                    .error(
413:                                            "Transaction Manager registerSynchronization() failed.",
414:                                            se);
415:                            throw new SystemException(se);
416:                        } catch (RollbackException re) {
417:                            throw new ApplicationException(
418:                                    new TransactionRolledbackException(re));
419:                        }
420:
421:                        txReadyPool.put(key, wrapper);
422:                    }
423:                } else {
424:                    /*
425:                    If there is no transaction associated with the thread OR if the operation was a find or home method (PrimaryKey == null)
426:                    Then the bean instance is simply returned to the methodReady pool
427:                     */
428:
429:                    if (primaryKey != null
430:                            && callContext.getCurrentOperation() != Operation.REMOVE) {
431:                        /*
432:                         * If the bean has a primary key; And its not being returned following a remove operation;
433:                         * then the bean is being returned to the method ready pool after successfully executing a business method or create
434:                         * method. In this case we need to call the bean instance's ejbPassivate before returning it to the pool per EJB 1.1
435:                         * Section 9.1.
436:                         */
437:                        Operation currentOp = callContext.getCurrentOperation();
438:
439:                        callContext.setCurrentOperation(Operation.PASSIVATE);
440:                        BaseContext.State[] originalStates = callContext
441:                                .setCurrentAllowedStates(EntityContext
442:                                        .getStates());
443:
444:                        try {
445:                            /*
446:                            In the event of an exception, OpenEJB is required to log the exception, evict the instance,
447:                            and mark the transaction for rollback.  If there is a transaction to rollback, then the a
448:                            javax.transaction.TransactionRolledbackException must be throw to the client.
449:                            See EJB 1.1 specification, section 12.3.2
450:                             */
451:                            bean.ejbPassivate();
452:                        } catch (Throwable e) {
453:                            try {
454:                                Transaction tx = getTransactionManager()
455:                                        .getTransaction();
456:                                if (tx != null) {
457:                                    tx.setRollbackOnly();
458:                                    throw new ApplicationException(
459:                                            new TransactionRolledbackException(
460:                                                    "Reflection exception thrown while attempting to call ejbPassivate() on the instance",
461:                                                    e));
462:                                }
463:                            } catch (javax.transaction.SystemException se) {
464:                                logger
465:                                        .error(
466:                                                "Transaction Manager getTransaction() failed.",
467:                                                se);
468:                                throw new SystemException(se);
469:                            }
470:                            throw new ApplicationException(
471:                                    new RemoteException(
472:                                            "Reflection exception thrown while attempting to call ejbPassivate() on the instance. Exception message = "
473:                                                    + e.getMessage(), e));
474:                        } finally {
475:                            callContext.setCurrentOperation(currentOp);
476:                            callContext.setCurrentAllowedStates(originalStates);
477:                        }
478:                    }
479:
480:                    /*
481:                     * The bean is returned to the method ready pool if its returned after servicing a find, ejbHome, business or create
482:                     * method and is not still part of a tx.  While in the method ready pool the bean instance is not associated with a
483:                     * primary key and may be used to service a request for any bean of the same class.
484:                     */
485:                    Stack methodReadyPool = poolMap.get(callContext
486:                            .getDeploymentInfo().getDeploymentID());
487:                    methodReadyPool.push(bean);
488:                }
489:
490:            }
491:
492:            public void freeInstance(ThreadContext callContext, EntityBean bean)
493:                    throws SystemException {
494:
495:                discardInstance(callContext, bean);
496:
497:                Operation currentOp = callContext.getCurrentOperation();
498:                callContext.setCurrentOperation(Operation.UNSET_CONTEXT);
499:                BaseContext.State[] originalStates = callContext
500:                        .setCurrentAllowedStates(EntityContext.getStates());
501:
502:                try {
503:                    /*
504:                     * unsetEntityContext executes in an unspecified transactional context. In this case we choose to
505:                     * allow it to have what every transaction context is current. Better then suspending it
506:                     * unnecessarily.
507:                     *
508:                     * We also chose not to invoke EntityContainer.invoke( ) method, which duplicate the exception handling
509:                     * logic but also attempt to manage the begining and end of a transaction. It its a container managed transaciton
510:                     * we don't want the TransactionScopeHandler commiting the transaction in afterInvoke() which is what it would attempt
511:                     * to do.
512:                     */
513:                    bean.unsetEntityContext();
514:                } catch (Exception e) {
515:                    /*
516:                     * The EJB 1.1 specification does not specify how exceptions thrown by unsetEntityContext impact the
517:                     * transaction, if there is one.  In this case we choose to do nothing since the instance is being disposed
518:                     * of anyway.
519:                     */
520:
521:                    logger.info(getClass().getName()
522:                            + ".freeInstance: ignoring exception " + e
523:                            + " on bean instance " + bean);
524:                } finally {
525:                    callContext.setCurrentOperation(currentOp);
526:                    callContext.setCurrentAllowedStates(originalStates);
527:                }
528:
529:            }
530:
531:            public void discardInstance(ThreadContext callContext,
532:                    EntityBean bean) throws SystemException {
533:                Transaction currentTx = null;
534:                try {
535:                    currentTx = getTransactionManager().getTransaction();
536:                } catch (javax.transaction.SystemException se) {
537:                    logger.error(
538:                            "Transaction Manager getTransaction() failed.", se);
539:                    throw new SystemException("TransactionManager failure", se);
540:                }
541:                if (currentTx != null) {
542:                    if (callContext.getPrimaryKey() == null)
543:                        return;
544:
545:                    Key key = new Key(currentTx, callContext
546:                            .getDeploymentInfo().getDeploymentID(), callContext
547:                            .getPrimaryKey());
548:
549:                    /*
550:                       The wrapper is removed (if pooled) so that it can not be accessed again. This is
551:                       especially important in the obtainInstance( ) method where a disassociated wrapper
552:                       in the txReadyPool is indicative of an entity bean that has been removed via
553:                       ejbRemove() rather than freed because of an error condition as is the case here.
554:                     */
555:                    SyncronizationWrapper wrapper = txReadyPool.remove(key);
556:
557:                    if (wrapper != null) {
558:                        /*
559:                         It's not possible to deregister a wrapper with the transaction,
560:                         but it can be removed from the tx pool and made inoperative by
561:                         calling its disassociate method. The wrapper will be returned to the
562:                         wrapper pool after the transaction completes
563:                         (see SynchronizationWrapper.afterCompletion( ) method).  The wrapper must
564:                         be returned after the transaction completes so that it is not in the service
565:                         of another bean when the TransactionManager calls its Synchronization methods.
566:
567:                         In addition, the bean instance is dereferenced so it can be garbage
568:                         collected.
569:                         */
570:                        wrapper.disassociate();
571:                    }
572:                }
573:            }
574:
575:            private TransactionManager getTransactionManager() {
576:                return transactionManager;
577:            }
578:
579:            /*
580:             * Instances of this class are used as keys for storing bean instances in the tx method
581:             * ready pool.  A compound key composed of the transaction, primary key, and deployment id
582:             * identifiers is required to uniquely identify a bean in the tx method ready pool.
583:             */
584:            public static class Key {
585:                private final Object deploymentID;
586:                private final Object primaryKey;
587:                private final Transaction transaction;
588:
589:                public Key(Transaction tx, Object depID, Object prKey) {
590:                    if (tx == null || depID == null || prKey == null) {
591:                        throw new IllegalArgumentException();
592:                    }
593:                    transaction = tx;
594:                    deploymentID = depID;
595:                    primaryKey = prKey;
596:                }
597:
598:                public Object getPK() {
599:                    return primaryKey;
600:                }
601:
602:                public int hashCode() {
603:                    return transaction.hashCode() ^ deploymentID.hashCode()
604:                            ^ primaryKey.hashCode();
605:                }
606:
607:                public boolean equals(Object other) {
608:                    if (other != null
609:                            && other.getClass() == EntityInstanceManager.Key.class) {
610:                        Key otherKey = (Key) other;
611:                        if (otherKey.transaction.equals(transaction)
612:                                && otherKey.deploymentID.equals(deploymentID)
613:                                && otherKey.primaryKey.equals(primaryKey))
614:                            return true;
615:                    }
616:                    return false;
617:                }
618:            }
619:
620:            /*
621:             * Instances of this class are used to wrap entity instances so that they can be registered
622:             * with a tx.  When the Synchronization.beforeCompletion is called, the bean's ejbStore method
623:             * is invoked.  When the Synchroniztion.afterCompletion is called, the bean instance is returned
624:             * to the method ready pool. Instances of this class are not recycled anymore, because modern VMs
625:             * (JDK1.3 and above) perform better for objects that are short lived.
626:             */
627:            protected class SyncronizationWrapper implements  Synchronization {
628:                private EntityBean bean;
629:                /*
630:                 * <tt>isAvailable<tt> determines if the wrapper is still associated with a bean.  If the bean identity is removed (ejbRemove)
631:                 * or if the bean instance is discarded, the wrapper will not longer be associated with a bean instances
632:                 * and therefore its beforeCompletion method will not process the ejbStore method.
633:                 */
634:                private boolean available;
635:                private boolean associated;
636:                private final Key readyPoolIndex;
637:                private final CoreDeploymentInfo deploymentInfo;
638:                private final Object primaryKey;
639:
640:                public SyncronizationWrapper(CoreDeploymentInfo deploymentInfo,
641:                        Object primaryKey, EntityBean bean, boolean available,
642:                        Key readyPoolIndex) {
643:                    if (bean == null)
644:                        throw new IllegalArgumentException("bean is null");
645:                    if (readyPoolIndex == null)
646:                        throw new IllegalArgumentException("key is null");
647:                    if (deploymentInfo == null)
648:                        throw new IllegalArgumentException(
649:                                "deploymentInfo is null");
650:                    if (primaryKey == null)
651:                        throw new IllegalArgumentException("primaryKey is null");
652:
653:                    this .deploymentInfo = deploymentInfo;
654:                    this .bean = bean;
655:                    this .primaryKey = primaryKey;
656:                    this .available = available;
657:                    this .readyPoolIndex = readyPoolIndex;
658:                    associated = true;
659:                }
660:
661:                public void associate() {
662:                    associated = true;
663:                }
664:
665:                public void disassociate() {
666:                    associated = false;
667:                }
668:
669:                public boolean isAssociated() {
670:                    return associated;
671:                }
672:
673:                public synchronized boolean isAvailable() {
674:                    return available;
675:                }
676:
677:                public synchronized void setEntityBean(EntityBean ebean) {
678:                    available = true;
679:                    bean = ebean;
680:                }
681:
682:                public synchronized EntityBean getEntityBean() {
683:                    available = false;
684:                    return bean;
685:                }
686:
687:                public void beforeCompletion() {
688:                    if (associated) {
689:                        EntityBean bean;
690:                        synchronized (this ) {
691:                            bean = this .bean;
692:                        }
693:
694:                        ThreadContext callContext = new ThreadContext(
695:                                deploymentInfo, primaryKey);
696:                        callContext.setCurrentOperation(Operation.STORE);
697:                        callContext.setCurrentAllowedStates(EntityContext
698:                                .getStates());
699:
700:                        ThreadContext oldCallContext = ThreadContext
701:                                .enter(callContext);
702:
703:                        try {
704:                            bean.ejbStore();
705:                        } catch (Exception re) {
706:                            logger.error("Exception occured during ejbStore()",
707:                                    re);
708:                            TransactionManager transactionManager = getTransactionManager();
709:                            try {
710:                                transactionManager.setRollbackOnly();
711:                            } catch (javax.transaction.SystemException se) {
712:                                logger
713:                                        .error(
714:                                                "Transaction manager reported error during setRollbackOnly()",
715:                                                se);
716:                            }
717:
718:                        } finally {
719:                            ThreadContext.exit(oldCallContext);
720:                        }
721:                    }
722:                }
723:
724:                public void afterCompletion(int status) {
725:                    txReadyPool.remove(readyPoolIndex);
726:                }
727:            }
728:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.