Source Code Cross Referenced for JEntitySwitch.java in  » J2EE » JOnAS-4.8.6 » org » objectweb » jonas_ejb » container » 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 » JOnAS 4.8.6 » org.objectweb.jonas_ejb.container 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /**
0002:         * JOnAS: Java(TM) Open Application Server
0003:         * Copyright (C) 1999 Bull S.A.
0004:         * Contact: jonas-team@objectweb.org
0005:         *
0006:         * This library is free software; you can redistribute it and/or
0007:         * modify it under the terms of the GNU Lesser General Public
0008:         * License as published by the Free Software Foundation; either
0009:         * version 2.1 of the License, or any later version.
0010:         *
0011:         * This library is distributed in the hope that it will be useful,
0012:         * but WITHOUT ANY WARRANTY; without even the implied warranty of
0013:         * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0014:         * Lesser General Public License for more details.
0015:         *
0016:         * You should have received a copy of the GNU Lesser General Public
0017:         * License along with this library; if not, write to the Free Software
0018:         * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
0019:         * USA
0020:         *
0021:         * --------------------------------------------------------------------------
0022:         * $Id: JEntitySwitch.java 10144 2007-04-05 06:48:57Z durieuxp $
0023:         * --------------------------------------------------------------------------
0024:         */package org.objectweb.jonas_ejb.container;
0025:
0026:        import java.rmi.NoSuchObjectException;
0027:        import java.rmi.RemoteException;
0028:        import java.util.ArrayList;
0029:        import java.util.ConcurrentModificationException;
0030:        import java.util.Iterator;
0031:
0032:        import javax.ejb.EJBException;
0033:        import javax.ejb.EntityBean;
0034:        import javax.ejb.NoSuchObjectLocalException;
0035:        import javax.ejb.ObjectNotFoundException;
0036:        import javax.ejb.TimedObject;
0037:        import javax.ejb.Timer;
0038:        import javax.ejb.TimerService;
0039:        import javax.transaction.Status;
0040:        import javax.transaction.SystemException;
0041:        import javax.transaction.Transaction;
0042:
0043:        import org.objectweb.jonas_ejb.deployment.api.EntityDesc;
0044:        import org.objectweb.jonas_timer.TraceTimer;
0045:        import org.objectweb.util.monolog.api.BasicLevel;
0046:
0047:        /**
0048:         * JEntitySwitch is used internally to synchronize accesses to the entity
0049:         * context and thus to the entity bean instance. All parts common to EJBObject
0050:         * and EJBLocalObject should be here. Different policies can be applied to
0051:         * manage context/instance pairs: - only 1 pair (container manages the
0052:         * transaction isolation) - 1 pair for each transaction (transaction isolation
0053:         * managed by DataBase) - 2 pairs (1 for transactional accesses, 1 for non
0054:         * transaction accesses)
0055:         * @author Philippe Durieux
0056:         * @author Philippe Coq
0057:         */
0058:        public abstract class JEntitySwitch {
0059:
0060:            /**
0061:             * The Factory for this bean
0062:             */
0063:            protected JEntityFactory bf;
0064:
0065:            /**
0066:             * The Primary Key for this bean instance.
0067:             */
0068:            protected Object pk = null;
0069:
0070:            /**
0071:             * The EJBLocalObject, or null if bean has no local interface.
0072:             */
0073:            protected JEntityLocal local = null;
0074:
0075:            /**
0076:             * The EJBObject, or null if bean has no remote interface.
0077:             */
0078:            protected JEntityRemote remote = null;
0079:
0080:            /**
0081:             * time in millisec. to keep objects in memory when not used.
0082:             * After this time, objects are freed, if instances have been passivated
0083:             * before.
0084:             */
0085:            protected long inactivityTimeout; // millisec.
0086:
0087:            /**
0088:             * time in millisec. to keep objects in memory without rereading them
0089:             * (for RO policy only)
0090:             */
0091:            protected long readTimeout; // millisec.
0092:
0093:            /**
0094:             * shared=true if the bean can be modify outside this container.
0095:             */
0096:            protected boolean shared;
0097:
0098:            /**
0099:             * Lock policy used for this entity bean. Possible values are :
0100:             * <dl>
0101:             * <li>0 = LOCK_CONTAINER_READ_UNCOMMITTED (1 instance) </li>
0102:             * <li>1 = LOCK_CONTAINER_SERIALIZED (1 instance) </li>
0103:             * <li>2 = LOCK_CONTAINER_READ_COMMITTED (2 instances) </li>
0104:             * <li>3 = LOCK_DATABASE (n instances) </li>
0105:             * <li>4 = LOCK_READ_ONLY (1 instance) </li>
0106:             * <li>5 = LOCK_CONTAINER_READ_WRITE (1 instance) </li>
0107:             * <li>6 = LOCK_CONTAINER_SERIALIZED_TRANSACTED (1 instance) </li>
0108:             * </dl>
0109:             */
0110:            protected int lockpolicy;
0111:
0112:            /**
0113:             * True if a transaction is mandatory for all modifying methods. In this
0114:             * case, all methods outside tranction is considered as read-only.
0115:             * Only CS policy has txUpdates=false.
0116:             */
0117:            protected boolean txUpdates = true;
0118:
0119:            /**
0120:             * The Timer Service
0121:             */
0122:            protected TimerService myTimerService = null;
0123:
0124:            /**
0125:             * nb of non transacted requests running
0126:             */
0127:            protected int countIH = 0;
0128:
0129:            /**
0130:             * nb of transacted requests running
0131:             */
0132:            protected int countIT = 0;
0133:
0134:            /**
0135:             * nb of threads waiting (synchronization)
0136:             */
0137:            protected int waiters = 0;
0138:
0139:            /**
0140:             * True if this instance may have been modified outside transactions. Avoids
0141:             * to put it twice in dirty list.
0142:             * Only used for CS policy (non transacted modifying methods)
0143:             */
0144:            protected boolean inDirtyList = false;
0145:
0146:            /**
0147:             * True if instance has been modified by a Transaction. This means that
0148:             * reading outside transaction should reload it before use.
0149:             * Only used for DB and CRC policies (non transacted instance)
0150:             */
0151:            protected boolean mustReload = false;
0152:
0153:            /**
0154:             * True if a TX need this instance currently used outside tx When the last
0155:             * release is done, we must store this instance.
0156:             * Only used when txUpdate is false (i.e. CS policy)
0157:             */
0158:            protected boolean mustStore = false;
0159:
0160:            /**
0161:             * True when context/instance has been discarded, to avoids that passivate
0162:             * store its state on storage.
0163:             */
0164:            protected boolean todiscard = false;
0165:
0166:            /**
0167:             * transaction on which a Context has been registered.
0168:             * Registration may be differed at first write in case of lazyregister=true.
0169:             * This ref is reset to null when the transaction is completed.
0170:             */
0171:            protected Transaction runningtx = null;
0172:
0173:            /**
0174:             * transaction that has modified an instance
0175:             */
0176:            protected Transaction writingtx = null;
0177:
0178:            // max time to wait when in a transaction, before checking for
0179:            // a deadlock.
0180:            protected long deadlockTimeout; // millisec.
0181:
0182:            /**
0183:             * List of all transactions currently blocked by runningtx
0184:             */
0185:            protected ArrayList blockedtx = new ArrayList();
0186:
0187:            /**
0188:             * True if this object will be garbaged and must not be used any longer.
0189:             */
0190:            protected boolean isremoved = false;
0191:
0192:            /**
0193:             * True if this object is no longer referenced by its factory, i.e.
0194:             * it is no longer in the PK list.
0195:             */
0196:            protected boolean isdetached = false;
0197:
0198:            // ident is used mainly for debugging
0199:            protected static int counter = 0;
0200:
0201:            protected String ident = "0000 ";
0202:
0203:            /**
0204:             * timestamp used to free objects when not used for a specified time.
0205:             */
0206:            protected long estimestamp = System.currentTimeMillis();
0207:
0208:            protected final static long FEW_SECONDS = 2000;
0209:
0210:            private static final int MAX_NB_RETRY = 2;
0211:
0212:            /**
0213:             * true if we can differ the registration at first write.
0214:             * Cannot be true if shared or prefetch.
0215:             */
0216:            protected boolean lazyregister = false;
0217:
0218:            /**
0219:             * reentrant=true if a bean instance can be accessed concurrently
0220:             * in the same transaction, or outside transaction.
0221:             */
0222:            protected boolean reentrant;
0223:
0224:            abstract JEntityContext getContext4Tx(Transaction tx);
0225:
0226:            abstract void setContext4Tx(Transaction tx, JEntityContext ctx);
0227:
0228:            abstract void removeContext4Tx(Transaction tx);
0229:
0230:            abstract protected void initpolicy(JEntityFactory bf);
0231:
0232:            /**
0233:             * @param store True if want to store instance first (CS policy)
0234:             * @param passivate True if we want to passivate instance
0235:             * @return result of operation: ALL_DONE, STORED, or NOT_DONE
0236:             */
0237:            abstract public int passivateIH(boolean store, boolean passivate);
0238:
0239:            /**
0240:             * Called only for CS policy, after passivateIH
0241:             */
0242:            abstract public void endIH();
0243:
0244:            // Results from passivateIH
0245:            static final int ALL_DONE = 0;
0246:            static final int STORED = 1;
0247:            static final int NOT_DONE = 2;
0248:
0249:            /**
0250:             * empty constructor. Object is initialized via init() because it is
0251:             * implemented differently according to jorm mappers.
0252:             */
0253:            public JEntitySwitch() {
0254:            }
0255:
0256:            /**
0257:             * constructor. A new object is build when a new PK is known in the
0258:             * container, either when a new bean is created, or when a find occurs. For
0259:             * create(), PK is not known yet when this object is build.
0260:             * @param bf The Entity Factory
0261:             * @param pk The Primary Key
0262:             */
0263:            public void init(JEntityFactory bf, Object pk) {
0264:                this .bf = bf;
0265:                this .pk = pk;
0266:                isremoved = false;
0267:                if (pk == null) {
0268:                    TraceEjb.logger.log(BasicLevel.ERROR,
0269:                            "Init Entity Switch with a null PK!");
0270:                    throw new EJBException("Init Entity Switch with a null PK!");
0271:                }
0272:
0273:                shared = bf.isShared();
0274:                reentrant = bf.isReentrant();
0275:                inactivityTimeout = bf.getInactivityTimeout() * 1000;
0276:                deadlockTimeout = bf.getDeadlockTimeout() * 1000;
0277:                readTimeout = bf.getReadTimeout() * 1000;
0278:                initpolicy(bf);
0279:                if (TraceEjb.isDebugSynchro() || TraceEjb.isDebugTx()) {
0280:                    // generate new ident (debug)
0281:                    String pks = pk.toString();
0282:                    ident = "<" + counter + ":" + pks + "> ";
0283:                }
0284:                counter++;
0285:
0286:                countIH = 0;
0287:                countIT = 0;
0288:                waiters = 0;
0289:
0290:                // Create EJBObject if bean has a Remote Interface
0291:                if (bf.getHome() != null) {
0292:                    try {
0293:                        remote = ((JEntityHome) bf.getHome())
0294:                                .createRemoteObject();
0295:                        remote.setEntitySwitch(this );
0296:                    } catch (RemoteException e) {
0297:                        throw new EJBException("cannot create Remote Object", e);
0298:                    }
0299:                }
0300:
0301:                // Create EJBLocalObject if bean has a Local Interface
0302:                if (bf.getLocalHome() != null) {
0303:                    local = ((JEntityLocalHome) bf.getLocalHome())
0304:                            .createLocalObject();
0305:                    local.setEntitySwitch(this );
0306:                }
0307:                // Set the timestamp to a big value because instance will be used.
0308:                // This solve a problem in case of findAll() for example :
0309:                // Avoids to discard instance just before it will be used.
0310:                estimestamp = System.currentTimeMillis() + FEW_SECONDS;
0311:            }
0312:
0313:            /**
0314:             * @return true if lazy registering enabled.
0315:             */
0316:            public boolean lazyRegistering() {
0317:                return lazyregister;
0318:            }
0319:
0320:            /**
0321:             * @return the underlaying EJBLocalObject
0322:             */
0323:            public JEntityLocal getLocal() {
0324:                return local;
0325:            }
0326:
0327:            /**
0328:             * @return the underlaying EJBObject
0329:             */
0330:            public JEntityRemote getRemote() {
0331:                return remote;
0332:            }
0333:
0334:            /**
0335:             * Obtains the TimerService associated for this Entity Bean (one / pk)
0336:             * @return a JTimerService instance.
0337:             */
0338:            public TimerService getEntityTimerService() {
0339:                // In case this object is used for a finder method,
0340:                // pk should be null, and TimerService must not be retrieved.
0341:                if (pk == null) {
0342:                    throw new java.lang.IllegalStateException();
0343:                }
0344:                if (myTimerService == null) {
0345:                    // TODO : Check that instance implements TimedObject ?
0346:                    myTimerService = new JTimerService(this );
0347:                }
0348:                return myTimerService;
0349:            }
0350:
0351:            /**
0352:             * This transaction has just modified this instance. (CMP2 only)
0353:             * Called only if lazyRegister is set and not RO policy.
0354:             * @param tx transaction
0355:             */
0356:            public synchronized void notifyWriting(Transaction tx,
0357:                    JEntityContext bctx) {
0358:                TraceEjb.synchro.log(BasicLevel.DEBUG, ident);
0359:                if (writingtx != null) {
0360:                    // If same tx, we have been called for nothing because
0361:                    // we are already registered (dirty=true)
0362:                    if (!tx.equals(writingtx)) {
0363:                        TraceEjb.logger.log(BasicLevel.WARN, "Conflict with "
0364:                                + writingtx);
0365:                        TraceEjb.logger.log(BasicLevel.WARN, "Current Tx is "
0366:                                + tx);
0367:                        try {
0368:                            tx.setRollbackOnly();
0369:                        } catch (SystemException e) {
0370:                            TraceEjb.logger
0371:                                    .log(BasicLevel.ERROR,
0372:                                            "cannot set current transaction RollbackOnly");
0373:                        }
0374:                        // Don't rollback writingtx, because no change has been done yet by tx.
0375:                        // This works only if setDirty is always called before modifications.
0376:                        throw new EJBException("Conflict writing entity bean");
0377:                    }
0378:                } else {
0379:                    if (lazyregister) {
0380:                        if (TraceEjb.isDebugTx()) {
0381:                            TraceEjb.tx.log(BasicLevel.DEBUG, ident
0382:                                    + " Register Ctx on " + tx);
0383:                        }
0384:                        registerCtx(tx, bctx);
0385:                    }
0386:                    if (TraceEjb.isDebugTx()) {
0387:                        TraceEjb.tx.log(BasicLevel.DEBUG, ident
0388:                                + " Set writingtx");
0389:                    }
0390:                    writingtx = tx;
0391:                }
0392:
0393:            }
0394:
0395:            /**
0396:             * Notify a timeout for this bean and this Pk
0397:             * @param timer timer whose expiration caused this notification.
0398:             */
0399:            public void notifyTimeout(Timer timer) {
0400:                if (bf.isStopped()) {
0401:                    TraceTimer.logger
0402:                            .log(BasicLevel.DEBUG, "Container stopped");
0403:                    return;
0404:                }
0405:                if (isremoved) {
0406:                    TraceTimer.logger.log(BasicLevel.DEBUG, "Bean is removed");
0407:                    return;
0408:                }
0409:                if (TraceTimer.isDebug()) {
0410:                    TraceTimer.logger.log(BasicLevel.DEBUG, ident);
0411:                }
0412:
0413:                boolean committed = false;
0414:                for (int nbretry = 0; !committed && nbretry < MAX_NB_RETRY; nbretry++) {
0415:                    RequestCtx rctx = bf.preInvoke(bf.getTimerTxAttribute());
0416:                    try {
0417:                        JEntityContext bctx = getICtx(rctx.currTx, false);
0418:                        EntityBean eb = bctx.getInstance();
0419:                        bf.checkSecurity(null);
0420:                        if (eb instanceof  TimedObject) {
0421:                            TimedObject instance = (TimedObject) eb;
0422:                            instance.ejbTimeout(timer);
0423:                        } else {
0424:                            throw new EJBException(
0425:                                    "The bean does not implement the `TimedObject` interface");
0426:                        }
0427:                        committed = (rctx.currTx == null)
0428:                                || (rctx.currTx.getStatus() != Status.STATUS_MARKED_ROLLBACK);
0429:                    } catch (EJBException e) {
0430:                        rctx.sysExc = e;
0431:                        throw e;
0432:                    } catch (RuntimeException e) {
0433:                        rctx.sysExc = e;
0434:                        throw new EJBException(
0435:                                "RuntimeException thrown by an enterprise Bean",
0436:                                e);
0437:                    } catch (Error e) {
0438:                        rctx.sysExc = e;
0439:                        throw new EJBException(
0440:                                "Error thrown by an enterprise Bean" + e);
0441:                    } catch (RemoteException e) {
0442:                        rctx.sysExc = e;
0443:                        throw new EJBException("Remote Exception raised:", e);
0444:                    } catch (SystemException e) {
0445:                        rctx.sysExc = e;
0446:                        throw new EJBException(
0447:                                "Cannot get transaction status:", e);
0448:                    } finally {
0449:                        try {
0450:                            bf.postInvoke(rctx);
0451:                        } finally {
0452:                            releaseICtx(rctx.currTx, rctx.sysExc != null);
0453:                        }
0454:                    }
0455:                }
0456:            }
0457:
0458:            /**
0459:             * @return the Primary Key Object for this instance.
0460:             */
0461:            public Object getPrimaryKey() {
0462:                if (pk == null) {
0463:                    throw new java.lang.IllegalStateException();
0464:                }
0465:                return pk;
0466:            }
0467:
0468:            /**
0469:             * bind a JEntityContext for a create method.
0470:             * @param tx - the Transaction object
0471:             * @param bctx - the JEntityContext to bind
0472:             */
0473:            public void bindICtx(Transaction tx, JEntityContext bctx) {
0474:                if (TraceEjb.isDebugSynchro()) {
0475:                    TraceEjb.synchro.log(BasicLevel.DEBUG, ident + " tx=" + tx);
0476:                }
0477:                mapICtx(tx, bctx, true, false, false);
0478:            }
0479:
0480:            /**
0481:             * Try to bind a JEntityContext if none already bound. Called by finder
0482:             * methods. This is actually kind of optimization.
0483:             * Can be bypassed if problems: just return false.
0484:             * @param tx - the Transaction object
0485:             * @param bctx The Entity Context
0486:             * @param simple True if simple finder method
0487:             * @return true if context has been bound to this EntitySwitch.
0488:             */
0489:            public synchronized boolean tryBindICtx(Transaction tx,
0490:                    JEntityContext bctx, boolean simple)
0491:                    throws ObjectNotFoundException {
0492:
0493:                if (TraceEjb.isDebugSynchro()) {
0494:                    TraceEjb.synchro.log(BasicLevel.DEBUG, ident + " tx=" + tx);
0495:                }
0496:
0497:                // Don't bind if already a context.
0498:                if (getContext4Tx(tx) != null) {
0499:                    if (TraceEjb.isDebugContext()) {
0500:                        TraceEjb.context.log(BasicLevel.DEBUG, ident
0501:                                + "context already mapped!");
0502:                    }
0503:                    if (getContext4Tx(tx).isMarkedRemoved()) {
0504:                        if (TraceEjb.isDebugContext()) {
0505:                            TraceEjb.context.log(BasicLevel.DEBUG, ident
0506:                                    + " currently being removed");
0507:                        }
0508:                        if (simple) {
0509:                            throw new ObjectNotFoundException(
0510:                                    "Instance is currently being removed");
0511:                        } else {
0512:                            // Don't throw exception in case of finder multiple.
0513:                            return false;
0514:                        }
0515:                    }
0516:                    // bctx will be released by caller. (See JEntityHome.vm)
0517:                    return false;
0518:                }
0519:
0520:                // No synchronization, since this is used for readonly methods (finder);
0521:                boolean isdirty = false;
0522:                try {
0523:                    isdirty = bctx.initEntityContext(this );
0524:                    bctx.activate(true);
0525:                } catch (Exception e) {
0526:                    TraceEjb.synchro.log(BasicLevel.WARN, ident
0527:                            + "Cannot bind Ctx: " + e);
0528:                    return false;
0529:                }
0530:                setContext4Tx(tx, bctx); // after activate (CRU => full parallellism)
0531:                if (!lazyregister || isdirty) {
0532:                    if (tx == null) {
0533:                        if (TraceEjb.isDebugSynchro()) {
0534:                            TraceEjb.synchro.log(BasicLevel.DEBUG, ident
0535:                                    + "IH find");
0536:                        }
0537:                    } else {
0538:                        if (TraceEjb.isDebugTx()) {
0539:                            TraceEjb.tx.log(BasicLevel.DEBUG, ident
0540:                                    + "IT find: registerCtx");
0541:                        }
0542:                        registerCtx(tx, bctx);
0543:                    }
0544:                }
0545:                return true;
0546:            }
0547:
0548:            /**
0549:             * bind a JEntityContext for a remove method. called in case of remove(pk)
0550:             * or remove(handle)
0551:             * @param tx - the Transaction object
0552:             * @param newctx - the JEntityContext to bind
0553:             * @return the BeanContext
0554:             */
0555:            public JEntityContext getICtx(Transaction tx, JEntityContext newctx) {
0556:                return mapICtx(tx, newctx, false, false, false);
0557:            }
0558:
0559:            /**
0560:             * Get a context/instance associated with this transaction Called at each
0561:             * request on the bean (including remove)
0562:             * @param tx - the Transaction object
0563:             * @param checkr - true if we must check non-reentrance.
0564:             * @return the BeanContext
0565:             */
0566:            public JEntityContext getICtx(Transaction tx, boolean checkr) {
0567:                return mapICtx(tx, null, false, true, checkr);
0568:            }
0569:
0570:            /**
0571:             * Release completely this object, since another one will be used.
0572:             * this occurs in case of create, when another EntitySwitch exist
0573:             * already.
0574:             * @param tx - the Transaction object
0575:             */
0576:            public synchronized boolean terminate(Transaction tx) {
0577:                TraceEjb.synchro.log(BasicLevel.DEBUG, ident);
0578:                waitmyturn(tx);
0579:                JEntityContext jec = getContext4Tx(tx);
0580:                if (jec != null) {
0581:                    if (todiscard || jec.isMarkedRemoved()) {
0582:                        TraceEjb.logger.log(BasicLevel.DEBUG,
0583:                                "will discardContext");
0584:                        discardContext(tx, true, true);
0585:                    } else {
0586:                        try {
0587:                            jec.storeIfModified();
0588:                        } catch (Exception e) {
0589:                            TraceEjb.logger.log(BasicLevel.ERROR, ident,
0590:                                    "error while storing bean state:", e);
0591:                        }
0592:                        jec.passivate();
0593:                        discardContext(tx, false, true);
0594:                    }
0595:                    if (waiters > 0) {
0596:                        if (TraceEjb.isDebugSynchro()) {
0597:                            TraceEjb.synchro.log(BasicLevel.DEBUG, ident
0598:                                    + " notify");
0599:                        }
0600:                        notifyAll();
0601:                    }
0602:                }
0603:                return true;
0604:            }
0605:
0606:            abstract void waitmyturn(Transaction tx);
0607:
0608:            /**
0609:             * Map a context and its instance.
0610:             * @param tx - the Transaction object
0611:             * @param bctx - the JEntityContext to bind if not null
0612:             * @param forced - force to take this context. (case of create)
0613:             * @param holdit - increment count to hold it, a release will be called
0614:             *        later.
0615:             * @param checkreentrance - true if we must check non-reentrance.
0616:             * @return JEntityContext actually mapped
0617:             */
0618:            public synchronized JEntityContext mapICtx(Transaction tx,
0619:                    JEntityContext bctx, boolean forced, boolean holdit,
0620:                    boolean checkreentrance) {
0621:
0622:                try {
0623:                    // DEBUG only
0624:                    if (bf == null) {
0625:                        TraceEjb.synchro.log(BasicLevel.ERROR,
0626:                                "JEntitySwitch not initialized!");
0627:                        throw new EJBException("JEntitySwitch not initialized");
0628:                    }
0629:                    if (TraceEjb.isDebugSynchro()) {
0630:                        TraceEjb.synchro.log(BasicLevel.DEBUG, ident + " tx="
0631:                                + tx);
0632:                    }
0633:
0634:                    // Check non-reentrance (See spec EJB 2.1 section 12.1.13)
0635:                    if (!reentrant && checkreentrance) {
0636:                        if (runningtx != null && countIT > 0 && tx != null
0637:                                && tx.equals(runningtx)) {
0638:                            throw new EJBException(
0639:                                    "non-reentrant bean accessed twice in same transaction");
0640:                        }
0641:                        if (tx == null && countIH > 0) {
0642:                            throw new EJBException(
0643:                                    "non-reentrant bean accessed twice outside transaction");
0644:                        }
0645:                    }
0646:                    // synchro (lock-policy dependant)
0647:                    waitmyturn(tx);
0648:
0649:                    // Set the timestamp to a big value because instance will be used.
0650:                    estimestamp = System.currentTimeMillis() + FEW_SECONDS;
0651:
0652:                    // Check the case where the object is detached
0653:                    if (isdetached) {
0654:                        JEntityFactory fact = (JEntityFactory) bf;
0655:                        JEntitySwitch old = fact
0656:                                .existEJB(getPrimaryKey(), this );
0657:                        if (old != null) {
0658:                            throw new NoSuchObjectLocalException(
0659:                                    "Inactivity timeout expired");
0660:                        }
0661:                        isdetached = false;
0662:                    }
0663:
0664:                    // Choose the context to use.
0665:                    boolean newtrans = false;
0666:                    boolean isdirty = false;
0667:                    JEntityContext jec = getContext4Tx(tx);
0668:                    if (forced) {
0669:                        // If the new context is enforced, we must first release the older
0670:                        if (jec != null) {
0671:                            if (TraceEjb.isDebugContext()) {
0672:                                TraceEjb.context.log(BasicLevel.DEBUG, ident
0673:                                        + "new context is enforced!");
0674:                            }
0675:                            discardContext(tx, false, true);
0676:                        }
0677:                        jec = bctx;
0678:                        setContext4Tx(tx, jec);
0679:                        isdirty = jec.initEntityContext(this );
0680:                        newtrans = true;
0681:                        isremoved = false; // in case of create following a remove
0682:                    } else {
0683:                        // First check if bean still exists
0684:                        if (isremoved) {
0685:                            TraceEjb.logger.log(BasicLevel.WARN, ident
0686:                                    + " has been removed.");
0687:                            throw new NoSuchObjectLocalException(
0688:                                    "Try to access a bean previously removed");
0689:                        }
0690:                        if (jec != null) {
0691:                            if (todiscard) {
0692:                                TraceEjb.logger.log(BasicLevel.WARN, ident
0693:                                        + " has been discarded.");
0694:                                throw new NoSuchObjectLocalException(
0695:                                        "Try to access a bean previously discarded");
0696:                            }
0697:                            // Reuse the Context for this transaction.
0698:                            // If a context was supplied, release it first.
0699:                            if (bctx != null) {
0700:                                if (TraceEjb.isDebugContext()) {
0701:                                    TraceEjb.context.log(BasicLevel.DEBUG,
0702:                                            ident + " a context was supplied");
0703:                                }
0704:                                if (bctx.getMyTx() != null) {
0705:                                    TraceEjb.context.log(BasicLevel.WARN,
0706:                                            "Will forget Tx!");
0707:                                }
0708:                                bf.releaseJContext(bctx, 2);
0709:                            }
0710:                            // In case the same instance is used for all tx, must check if
0711:                            // new one. For LOCK_DATABASE policy, it cannot be a new tx.
0712:                            if (runningtx == null
0713:                                    && lockpolicy != EntityDesc.LOCK_DATABASE) {
0714:                                newtrans = true;
0715:                            }
0716:                            jec.reuseEntityContext(newtrans);
0717:                        } else {
0718:                            if (bctx != null) {
0719:                                jec = bctx;
0720:                            } else {
0721:                                // no Context available : get one from the pool.
0722:                                jec = bf.getJContext(this );
0723:                            }
0724:                            isdirty = jec.initEntityContext(this );
0725:                            jec.activate(true);
0726:                            setContext4Tx(tx, jec); // after activate
0727:                            newtrans = true;
0728:                        }
0729:                    }
0730:
0731:                    if (tx != null) {
0732:                        // Register Context now, except if no new transaction
0733:                        if (newtrans && (!lazyregister || isdirty)) {
0734:                            try {
0735:                                registerCtx(tx, jec);
0736:                                if (TraceEjb.isDebugSynchro()) {
0737:                                    TraceEjb.synchro
0738:                                            .log(
0739:                                                    BasicLevel.DEBUG,
0740:                                                    ident
0741:                                                            + "mapICtx IT: new tx, registerSynchronization");
0742:                                }
0743:                            } catch (IllegalStateException e) {
0744:                                if (TraceEjb.synchro
0745:                                        .isLoggable(BasicLevel.WARN)) {
0746:                                    TraceEjb.synchro.log(BasicLevel.WARN, ident
0747:                                            + "mapICtx IT: not registered!", e);
0748:                                }
0749:                            }
0750:                        }
0751:                    } else {
0752:                        if (holdit) {
0753:                            if (TraceEjb.isDebugSynchro()) {
0754:                                TraceEjb.synchro.log(BasicLevel.DEBUG, ident
0755:                                        + "mapICtx IH count=" + countIH);
0756:                            }
0757:                            if ((shared || mustReload) && countIH == 0) {
0758:                                // reload state that could have been modified by
0759:                                // transactions.
0760:                                jec.activate(false);
0761:                                mustReload = false;
0762:                            }
0763:                        }
0764:                        if (!inDirtyList && !txUpdates) {
0765:                            inDirtyList = true;
0766:                            bf.registerEJB(this );
0767:                        }
0768:                    }
0769:
0770:                    return jec;
0771:                } finally {
0772:                    if (holdit) {
0773:                        if (tx == null) {
0774:                            countIH++;
0775:                        } else {
0776:                            countIT++;
0777:                        }
0778:                    }
0779:                }
0780:            }
0781:
0782:            /**
0783:             * Look if the specified transaction is blocked.
0784:             * @param testedtx Transaction we look for
0785:             * @return The blocking transaction
0786:             */
0787:            public Transaction getBlockingTx(Transaction testedtx) {
0788:                Transaction ret = null;
0789:                if (runningtx != null && blockedtx.size() > 0) {
0790:                    try {
0791:                        for (Iterator i = blockedtx.iterator(); i.hasNext();) {
0792:                            Transaction tx = (Transaction) i.next();
0793:                            if (tx.equals(testedtx)) {
0794:                                ret = runningtx;
0795:                                break;
0796:                            }
0797:                        }
0798:                    } catch (ConcurrentModificationException e) {
0799:                        TraceEjb.synchro.log(BasicLevel.WARN,
0800:                                "Concurrent access. Will retry later.");
0801:                    }
0802:                }
0803:                return ret;
0804:            }
0805:
0806:            /**
0807:             * Release a context/instance at end of request.
0808:             * @param tx - transaction associated to this context
0809:             * @param discard - instance must be discarded
0810:             */
0811:            public synchronized void releaseICtx(Transaction tx, boolean discard) {
0812:
0813:                if (tx == null) {
0814:                    // ------------- IH end -------------
0815:                    countIH--;
0816:                    if (TraceEjb.isDebugSynchro()) {
0817:                        TraceEjb.synchro.log(BasicLevel.DEBUG, ident
0818:                                + " countIH=" + countIH);
0819:                    }
0820:                    if (countIH == 0) {
0821:                        JEntityContext jec = getContext4Tx(tx);
0822:                        if (jec == null) {
0823:                            TraceEjb.context.log(BasicLevel.ERROR, ident
0824:                                    + " No context!");
0825:                            Thread.dumpStack();
0826:                            return;
0827:                        }
0828:                        if (jec.isMarkedRemoved()) {
0829:                            discardContext(tx, true, true);
0830:                        } else if (todiscard || discard) {
0831:                            discardContext(tx, false, false);
0832:                        } else {
0833:                            if (mustStore) {
0834:                                // This is for CS policy only
0835:                                try {
0836:                                    jec.storeIfModified();
0837:                                } catch (EJBException e) {
0838:                                    if (TraceEjb.isVerbose()) {
0839:                                        TraceEjb.logger.log(BasicLevel.WARN,
0840:                                                ident + " ejbexception", e);
0841:                                    }
0842:                                }
0843:                                mustStore = false;
0844:                            }
0845:                            if (bf.tooManyInstances()) {
0846:                                // Passivate if max-cache-size has been reached.
0847:                                if (TraceEjb.isDebugContext()) {
0848:                                    TraceEjb.context.log(BasicLevel.DEBUG, jec
0849:                                            + " passivated!");
0850:                                }
0851:                                jec.passivate();
0852:                                if (jec.getMyTx() != null) {
0853:                                    TraceEjb.context.log(BasicLevel.WARN,
0854:                                            "Will forget Tx!");
0855:                                }
0856:                                bf.releaseJContext(jec, 0);
0857:                                removeContext4Tx(tx);
0858:                            }
0859:                        }
0860:                        if (waiters > 0) {
0861:                            if (TraceEjb.isDebugSynchro()) {
0862:                                TraceEjb.synchro.log(BasicLevel.DEBUG, ident
0863:                                        + " notify");
0864:                            }
0865:                            notifyAll();
0866:                        }
0867:                    } else {
0868:                        if (discard) {
0869:                            todiscard = true;
0870:                        }
0871:                    }
0872:                } else {
0873:                    // ------------- IT end -------------
0874:                    // nothing to do now. Wait for tx completed.
0875:                    countIT--;
0876:                    if (TraceEjb.isDebugSynchro()) {
0877:                        TraceEjb.synchro.log(BasicLevel.DEBUG, ident
0878:                                + " countIT=" + countIT);
0879:                    }
0880:                    if (runningtx != null && discard) {
0881:                        if (TraceEjb.isDebugTx()) {
0882:                            TraceEjb.tx.log(BasicLevel.DEBUG, ident
0883:                                    + " will be disarded when tx is over: "
0884:                                    + runningtx);
0885:                        }
0886:                        todiscard = true;
0887:                    }
0888:                }
0889:            }
0890:
0891:            public synchronized void forceDiscardICtx(Transaction tx) {
0892:                discardContext(tx, true, true);
0893:            }
0894:
0895:            /**
0896:             * This transaction is now over. We can dispose of the instance for another
0897:             * transaction or discard it.
0898:             * A special implementation exists for RO policy
0899:             * @param tx the transaction object
0900:             * @param committed true if transaction was committed.
0901:             */
0902:            public synchronized void txCompleted(Transaction tx,
0903:                    boolean committed) {
0904:                JEntityContext jec = getContext4Tx(tx);
0905:                if (jec == null) {
0906:                    TraceEjb.context.log(BasicLevel.ERROR, ident
0907:                            + " No context for this tx");
0908:                    return;
0909:                }
0910:                runningtx = null;
0911:                if (writingtx != null && tx.equals(writingtx)) {
0912:                    writingtx = null;
0913:                }
0914:
0915:                if (TraceEjb.isDebugSynchro()) {
0916:                    TraceEjb.synchro.log(BasicLevel.DEBUG, ident
0917:                            + (committed ? " commit" : " rollback"));
0918:                }
0919:
0920:                // The create was eventually rolled back or instance has been discarded.
0921:                // We must remove PK entry.
0922:                if (todiscard || (jec.isNewInstance() && !committed)) {
0923:                    if (TraceEjb.isDebugTx()) {
0924:                        TraceEjb.tx.log(BasicLevel.DEBUG, ident
0925:                                + " will be discarded");
0926:                    }
0927:                    if (writingtx != null) {
0928:                        TraceEjb.tx.log(BasicLevel.WARN, ident
0929:                                + " has a running tx:" + writingtx);
0930:                    }
0931:                    discardContext(tx, !todiscard, false);
0932:                    return;
0933:                }
0934:
0935:                if (jec.isMarkedRemoved()) {
0936:                    if (TraceEjb.isDebugContext()) {
0937:                        TraceEjb.context.log(BasicLevel.DEBUG, ident
0938:                                + " removed!");
0939:                    }
0940:                    discardContext(tx, committed, true);
0941:                } else {
0942:                    if (shared || !committed || bf.tooManyInstances()) {
0943:                        // Passivate when shared, or if max-cache-size has been reached.
0944:                        if (TraceEjb.isDebugContext()) {
0945:                            TraceEjb.context.log(BasicLevel.DEBUG, jec
0946:                                    + " passivated!");
0947:                        }
0948:                        jec.passivate();
0949:                        // context is discarded if transaction rolled back
0950:                        if (!committed && writingtx != null) {
0951:                            TraceEjb.tx.log(BasicLevel.WARN, ident
0952:                                    + " !!! Discard but has a running tx:"
0953:                                    + writingtx);
0954:                        }
0955:                        bf.releaseJContext(jec, committed ? 2 : 0);
0956:                        removeContext4Tx(tx);
0957:                    } else {
0958:                        // do this before reallocating the Context for another tx
0959:                        // (inside this lock)
0960:                        jec.detachTx();
0961:                    }
0962:                    // If special instance for no transactional accesses, it must be
0963:                    // reloaded
0964:                    if (lockpolicy == EntityDesc.LOCK_CONTAINER_READ_COMMITTED
0965:                            || lockpolicy == EntityDesc.LOCK_DATABASE) {
0966:                        mustReload = true;
0967:                    }
0968:                }
0969:                if (waiters > 0) {
0970:                    if (TraceEjb.isDebugSynchro()) {
0971:                        TraceEjb.synchro.log(BasicLevel.DEBUG, ident
0972:                                + " notify");
0973:                    }
0974:                    notifyAll();
0975:                }
0976:            }
0977:
0978:            /**
0979:             * register a Context on the transaction, as a Synchronization. this will be
0980:             * used later to store instance state when needed : before a finder, or at
0981:             * beforeCompletion, and to release instance at commit.
0982:             * @param tx Transaction object
0983:             * @param bctx The Context to be registered
0984:             */
0985:            protected void registerCtx(Transaction tx, JEntityContext bctx) {
0986:                // DEBUG only
0987:                if (bf == null) {
0988:                    TraceEjb.synchro.log(BasicLevel.ERROR,
0989:                            "JEntitySwitch not initialized!");
0990:                    throw new EJBException("JEntitySwitch not initialized");
0991:                }
0992:                // register this context to the transaction, as a Synchronization.
0993:                try {
0994:                    // Do this before, to test first if context still valid.
0995:                    if (!bctx.setRunningTx(tx)) {
0996:                        TraceEjb.context.log(BasicLevel.DEBUG, bctx
0997:                                + "already registered!");
0998:                        if (runningtx == null) {
0999:                            TraceEjb.context.log(BasicLevel.ERROR,
1000:                                    "runningtx = null");
1001:                        }
1002:                        return;
1003:                    }
1004:                    if (bf.registerContext(tx, bctx)) {
1005:                        if (TraceEjb.isDebugContext()) {
1006:                            TraceEjb.context.log(BasicLevel.DEBUG, bctx
1007:                                    + " registered!");
1008:                        }
1009:                        runningtx = tx;
1010:                    } else {
1011:                        TraceEjb.context.log(BasicLevel.WARN, bctx
1012:                                + " could not be registered!");
1013:                        bctx.setRunningTx(null);
1014:                    }
1015:                } catch (IllegalStateException e) {
1016:                    TraceEjb.logger.log(BasicLevel.ERROR, ident
1017:                            + "Transaction is in an illegal state");
1018:                    throw e;
1019:                }
1020:            }
1021:
1022:            /**
1023:             * Detach entity switch from PK list.
1024:             * This should trigger cleaning memory from all these objects by garbage collector.
1025:             */
1026:            protected void detachPk() {
1027:                TraceEjb.swapper.log(BasicLevel.DEBUG, ident
1028:                        + " discarded on timeout");
1029:
1030:                if (remote != null) {
1031:                    try {
1032:                        remote.unexportObject();
1033:                    } catch (NoSuchObjectException e) {
1034:                        TraceEjb.logger.log(BasicLevel.ERROR, ident
1035:                                + " unexport entity failed: ", e);
1036:                    }
1037:                }
1038:                bf.removeEJB(getPrimaryKey());
1039:
1040:                // this Entity switch can still be reached from another bean (CMR)
1041:                // In this case, we'll have to reconnect it to the PK list.
1042:                isdetached = true;
1043:            }
1044:
1045:            /**
1046:             * Discard instance/Context and free all objects.
1047:             * @param tx - the Transaction object
1048:             * @param forgetpk - true if remove pk from the list
1049:             * @param pool - true if instance can be pooled.
1050:             */
1051:            protected void discardContext(Transaction tx, boolean forgetpk,
1052:                    boolean pool) {
1053:                if (TraceEjb.isDebugTx()) {
1054:                    TraceEjb.tx.log(BasicLevel.DEBUG, "tx=" + tx);
1055:                }
1056:                JEntityContext jec = getContext4Tx(tx);
1057:                if (jec != null) {
1058:                    if (runningtx != null && tx != null && tx.equals(runningtx)) {
1059:                        // This Context is registered in the tx
1060:                        // Must remove it from the list before releasing it.
1061:                        bf.unregisterContext(runningtx, jec);
1062:                        runningtx = null;
1063:                    }
1064:                    bf.releaseJContext(jec, pool ? 2 : 0);
1065:                    removeContext4Tx(tx);
1066:                }
1067:                if (forgetpk) {
1068:                    if (remote != null) {
1069:                        try {
1070:                            remote.unexportObject();
1071:                        } catch (NoSuchObjectException e) {
1072:                            TraceEjb.logger.log(BasicLevel.ERROR, ident
1073:                                    + " unexport entity failed: ", e);
1074:                        }
1075:                    }
1076:                    bf.removeEJB(getPrimaryKey());
1077:
1078:                    // Cancel all timers for this bean (= remove the TimerService)
1079:                    if (myTimerService != null) {
1080:                        ((JTimerService) myTimerService).cancelAllTimers();
1081:                        myTimerService = null;
1082:                    }
1083:                    // this Entity switch must not be used any longer.
1084:                    isremoved = true;
1085:                }
1086:                todiscard = false; // done.
1087:            }
1088:
1089:            /**
1090:             * @return lock policy for this bean
1091:             */
1092:            public int getPolicy() {
1093:                return lockpolicy;
1094:            }
1095:
1096:            /**
1097:             * @return State of this instance. State values are 0=in-tx, 1=out-tx, 2=idle,
1098:             *         3=passive, 4=removed. we don't synchronize this method to avoid
1099:             *         jadmin blocks
1100:             */
1101:            abstract public int getState();
1102:
1103:            /**
1104:             * @return the JFactory
1105:             */
1106:            public JFactory getBeanFactory() {
1107:                return bf;
1108:            }
1109:
1110:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.