Source Code Cross Referenced for BOObjectDomainImpl.java in  » UML » MetaBoss » com » metaboss » enterprise » bo » impl » 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 » UML » MetaBoss » com.metaboss.enterprise.bo.impl 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        // THIS SOFTWARE IS PROVIDED BY SOFTARIS PTY.LTD. AND OTHER METABOSS
002:        // CONTRIBUTORS ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING,
003:        // BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
004:        // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SOFTARIS PTY.LTD.
005:        // OR OTHER METABOSS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
006:        // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
007:        // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
008:        // OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
009:        // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
010:        // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
011:        // EVEN IF SOFTARIS PTY.LTD. OR OTHER METABOSS CONTRIBUTORS ARE ADVISED OF THE
012:        // POSSIBILITY OF SUCH DAMAGE.
013:        //
014:        // Copyright 2000-2005 © Softaris Pty.Ltd. All Rights Reserved.
015:        package com.metaboss.enterprise.bo.impl;
016:
017:        import java.lang.reflect.Array;
018:        import java.lang.reflect.InvocationTargetException;
019:        import java.lang.reflect.Method;
020:        import java.util.ArrayList;
021:        import java.util.Collection;
022:        import java.util.HashMap;
023:        import java.util.Iterator;
024:        import java.util.List;
025:        import java.util.Map;
026:
027:        import javax.naming.NamingException;
028:
029:        import org.apache.commons.logging.Log;
030:        import org.apache.commons.logging.LogFactory;
031:
032:        import com.metaboss.enterprise.bo.BOException;
033:        import com.metaboss.enterprise.bo.BOInvalidOperationForObjectDomainBeingEditedException;
034:        import com.metaboss.enterprise.bo.BOInvalidOperationForObjectException;
035:        import com.metaboss.enterprise.bo.BOInvalidOperationForReadOnlyObjectDomainException;
036:        import com.metaboss.enterprise.bo.BONamingAndDirectoryServiceInvocationException;
037:        import com.metaboss.enterprise.bo.BONewObjectRequiredException;
038:        import com.metaboss.enterprise.bo.BOObjectAlreadyInTransactionException;
039:        import com.metaboss.enterprise.bo.BOObjectDomain;
040:        import com.metaboss.enterprise.bo.BOObjectDomainNotInTransactionException;
041:        import com.metaboss.enterprise.bo.BOObjectNotInTransactionException;
042:        import com.metaboss.enterprise.bo.BOObjectNotInitialisedException;
043:        import com.metaboss.enterprise.bo.BOObjectUnusableException;
044:        import com.metaboss.enterprise.bo.BOPersistenceServiceInvocationException;
045:        import com.metaboss.enterprise.bo.BOUnexpectedProgramConditionException;
046:        import com.metaboss.enterprise.ps.PSException;
047:
048:        /* Base implementation class for all BOs */
049:        public abstract class BOObjectDomainImpl implements  BOObjectDomain {
050:            // Static logging instance
051:            private static final Log sLogger = LogFactory
052:                    .getLog(BOObjectDomainImpl.class);
053:
054:            // The domain can be in one of the following states
055:            // Unusable state. Just constructed object has it.
056:            private static final int cStateNotSetUp = 0;
057:            // Read only domain.
058:            private static final int cStateReadOnly = 1;
059:            // Editable domain
060:            // After successfull commit and unsuccessfull commit bo will revert to  cStateReadOnly
061:            private static final int cStateBeingEdited = 2;
062:
063:            // The actual state variable
064:            private int mState = cStateNotSetUp;
065:            // The actual domain url variable
066:            private String mDomainType;
067:            // The store for the entities loaded in this domain
068:            private HashMap mEntities = new HashMap();
069:
070:            // Default constructor is disabled 
071:            private BOObjectDomainImpl() {
072:            }
073:
074:            // Domain Url is a unique id of the domain. 
075:            protected BOObjectDomainImpl(String pDomainType) throws BOException {
076:                mDomainType = pDomainType;
077:            }
078:
079:            // Getter for the domain type
080:            protected String getDomainType() throws BOException {
081:                return mDomainType;
082:            }
083:
084:            // Domain Url is globally unique identifier of the domain
085:            protected String getDomainUrl() throws BOException {
086:                return "domain:/" + mDomainType;
087:            }
088:
089:            // Registers newly loaded entity or throws exception if this entity is already loaded	
090:            public void addEntity(BOObjectImpl pEntity) throws BOException {
091:                HashMap lTypeInstances = (HashMap) mEntities.get(pEntity
092:                        .getEntityType());
093:                if (lTypeInstances == null)
094:                    mEntities.put(pEntity.getEntityType(),
095:                            lTypeInstances = new HashMap());
096:                if (lTypeInstances.containsKey(pEntity.getEntityInstanceId()))
097:                    throw new BOUnexpectedProgramConditionException(
098:                            "BOObject representing same record has already been instantiated in this domain.");
099:                lTypeInstances.put(pEntity.getEntityInstanceId(), pEntity);
100:            }
101:
102:            // Returns registered instance of the entity or null if nothing is registered	
103:            public BOObjectImpl getEntity(String pEntityType,
104:                    String pEntityInstanceId) throws BOException {
105:                HashMap lTypeInstances = (HashMap) mEntities.get(pEntityType);
106:                if (lTypeInstances == null)
107:                    return null;
108:                return (BOObjectImpl) lTypeInstances.get(pEntityInstanceId);
109:            }
110:
111:            // Returns collection of all entities of the given types.
112:            // The collection is empty if no entities are stored	
113:            // Supplied array of entity types allows to cater for the hierarchy of subclass entities
114:            public Collection getAllEntities(String[] pEntityTypes)
115:                    throws BOException {
116:                List lResultList = new ArrayList();
117:                for (int i = 0; i < pEntityTypes.length; i++) {
118:                    HashMap lTypeInstances = (HashMap) mEntities
119:                            .get(pEntityTypes[i]);
120:                    if (lTypeInstances != null)
121:                        lResultList.addAll(lTypeInstances.values());
122:                }
123:                return lResultList;
124:            }
125:
126:            // Returns registered instance of the entity with given natural primary key
127:            // Supplied array of entity types allows to cater for the hierarchy of subclass entities
128:            public BOObjectImpl getEntityWithNaturalPrimaryKey(
129:                    String[] pEntityTypes, Object[] pNaturalPrimaryKey)
130:                    throws BOException {
131:                for (int i = 0; i < pEntityTypes.length; i++) {
132:                    HashMap lTypeInstances = (HashMap) mEntities
133:                            .get(pEntityTypes[i]);
134:                    if (lTypeInstances != null) {
135:                        for (Iterator lTypeIterator = lTypeInstances.values()
136:                                .iterator(); lTypeIterator.hasNext();) {
137:                            BOObjectImpl lEntityObject = (BOObjectImpl) lTypeIterator
138:                                    .next();
139:                            Object[] lNaturalPrimaryKey = lEntityObject
140:                                    .getNaturalPrimaryKey();
141:                            if (lNaturalPrimaryKey == null
142:                                    || lNaturalPrimaryKey.length == 0)
143:                                throw new BOUnexpectedProgramConditionException(
144:                                        "Natural primary key is not expected to be empty");
145:                            boolean lMatch = true;
146:                            for (int j = 0; j < lNaturalPrimaryKey.length
147:                                    && lMatch == true; j++)
148:                                lMatch = pNaturalPrimaryKey[j]
149:                                        .equals(lNaturalPrimaryKey[j]);
150:                            if (lMatch)
151:                                return lEntityObject;
152:                        }
153:                    }
154:                }
155:                return null;
156:            }
157:
158:            // Returns registered instance of the entity or null if nothing is registered	
159:            public boolean containsEntity(String pEntityType,
160:                    String pEntityInstanceId) throws BOException {
161:                return getEntity(pEntityType, pEntityInstanceId) != null;
162:            }
163:
164:            // Returns registered instance of the entity or null if nothing is registered	
165:            // Supplied array of entity types allows to cater for the hierarchy of subclass entities
166:            public boolean containsEntityWithNaturalPrimaryKey(
167:                    String[] pEntityTypes, Object[] pNaturalPrimaryKey)
168:                    throws BOException {
169:                return getEntityWithNaturalPrimaryKey(pEntityTypes,
170:                        pNaturalPrimaryKey) != null;
171:            }
172:
173:            /* Returns true if object is read only representing an existing entity */
174:            public boolean isReadOnly() throws BOException {
175:                // This pattern of implementation does not waste time on unnecessary checks if object is in the right state
176:                // That means that the application, which knows what it is doing will not run unnecessary tests all the time
177:                if (mState == cStateReadOnly)
178:                    return true;
179:                checkValidState();
180:                return false;
181:            }
182:
183:            /* Returns true if object is in transaction and represents an existing entity which is being edited */
184:            public boolean isBeingEdited() throws BOException {
185:                // This pattern of implementation does not waste time on unnecessary checks if object is in the right state
186:                // That means that the application, which knows what it is doing will not run unnecessary tests all the time
187:                if (mState == cStateBeingEdited)
188:                    return true;
189:                checkValidState();
190:                return false;
191:            }
192:
193:            /* Returns if object is allowed to execute getter and throws exception if it is not */
194:            public void assertGetter() throws BOException {
195:                // This pattern of implementation does not waste time on unnecessary checks if object is in the right state
196:                // That means that the application, which knows what it is doing will not run unnecessary tests all the time
197:                if (mState == cStateReadOnly || mState == cStateBeingEdited)
198:                    return;
199:                throw createInvalidOperationException();
200:            }
201:
202:            /* Returns if object is allowed to execute getter and throws exception if it is not */
203:            public void assertSetter() throws BOException {
204:                // This pattern of implementation does not waste time on unnecessary checks if object is in the right state
205:                // That means that the application, which knows what it is doing will not run unnecessary tests all the time
206:                if (mState == cStateBeingEdited)
207:                    return;
208:                throw createInvalidOperationException();
209:            }
210:
211:            /*
212:             * This method must be called immediately after domain construction in order
213:             * to set it up as existing object. Object is setup as Existing / ReadOnly
214:             * in this case and therefore transaction is not required
215:             */
216:            public final void setupForExisting() throws BOException {
217:                // Check if we are in the right status
218:                if (mState != cStateNotSetUp)
219:                    throw new BONewObjectRequiredException(); // Attempt to set up the object second time
220:                mState = cStateReadOnly;
221:            }
222:
223:            /* Marks domain as editable and registers it with transaction */
224:            public final void beginEdit() throws BOException {
225:                // Allow multiple begin edits.
226:                if (isBeingEdited())
227:                    return;
228:                // You can only begin edit read only object
229:                if (!isReadOnly())
230:                    throw createInvalidOperationException();
231:                // Call the state transition method while not yet in the transaction
232:                onBeginEdit();
233:                // Get existing or create new internal transaction controller
234:                InternalTransactionController lTxController = InternalTransactionController
235:                        .getInstance();
236:                lTxController.registerDomain(this );
237:                mState = cStateBeingEdited;
238:            }
239:
240:            /** Saves changes if this domain object is editable. This method is forgiving in a sence that
241:             * if the deomain object is not editable it just returns silently. Useful in cases when
242:             * domain object is passed around the code (ie. processing code does not know what sate domain is in)
243:             * and there is a need to save changes */
244:            public final void saveChangesIfNecessary() throws BOException {
245:                // Just call the other method if we are editable
246:                if (isBeingEdited())
247:                    saveChanges();
248:            }
249:
250:            /* Saves changes collected from the most recent call to saveChanges() or beginEdit(),
251:             * whichever is most recent. The domain has no outstanding changes in memory after completion of
252:             * this call. Note that calling this method explicitly is not essential - 
253:             * it will be called automatically during transaction commit. Still, there may be
254:             * valid reasons to call this method explicitly:
255:             * <UL>
256:             * <LI>Caller wants to explicitly make sure that collected changes do not violate any database storage constraints</LI>
257:             * <LI>Caller wants to save all changes before executing database search</LI>
258:             * </UL>
259:             */
260:            public final void saveChanges() throws BOException {
261:                // We can only saveChanges on editable domain.
262:                if (!isBeingEdited())
263:                    throw createInvalidOperationException();
264:                sLogger
265:                        .debug("Commencing saving changes to all entities in the domain");
266:                sLogger.debug("Found " + mMainInstructionsList.size()
267:                        + " persistence instructions to execute.");
268:                try {
269:                    // Iterate through main list of PersistenceInstructions and execute them one by one
270:                    for (Iterator lInstructionsIterator = mMainInstructionsList
271:                            .iterator(); lInstructionsIterator.hasNext();) {
272:                        PersistenceInstruction lInstruction = (PersistenceInstruction) lInstructionsIterator
273:                                .next();
274:                        Object[] lBOImplArray = lInstruction.InstancesList
275:                                .toArray((Object[]) Array.newInstance(
276:                                        lInstruction.ImplClass,
277:                                        lInstruction.InstancesList.size()));
278:                        lInstruction.PersistenceMethod.invoke(null,
279:                                new Object[] { lBOImplArray });
280:                    }
281:                    // Iterate through deferred list of PersistenceInstructions and execute them one by one
282:                    for (Iterator lInstructionsIterator = mDeferredInstructionsList
283:                            .iterator(); lInstructionsIterator.hasNext();) {
284:                        PersistenceInstruction lInstruction = (PersistenceInstruction) lInstructionsIterator
285:                                .next();
286:                        Object[] lBOImplArray = lInstruction.InstancesList
287:                                .toArray((Object[]) Array.newInstance(
288:                                        lInstruction.ImplClass,
289:                                        lInstruction.InstancesList.size()));
290:                        lInstruction.PersistenceMethod.invoke(null,
291:                                new Object[] { lBOImplArray });
292:                    }
293:                    // Do save on all involved entities first
294:                    for (Iterator lInstructionsIterator = mMainInstructionsList
295:                            .iterator(); lInstructionsIterator.hasNext();) {
296:                        PersistenceInstruction lInstruction = (PersistenceInstruction) lInstructionsIterator
297:                                .next();
298:                        for (Iterator lBOImplsIterator = lInstruction.InstancesList
299:                                .iterator(); lBOImplsIterator.hasNext();) {
300:                            BOObjectImpl lBOImpl = (BOObjectImpl) lBOImplsIterator
301:                                    .next();
302:                            lBOImpl.doSave();
303:                        }
304:                    }
305:                    // Modify persistence instructions list to reflect the latest changes
306:                    // All entities with create instructions - populate with update instructions
307:                    // all entities with delete instructions - delete from the instructions list
308:                    mMainInstructionsList.doAfterSave();
309:                    mDeferredInstructionsList.doAfterSave();
310:                } catch (Throwable t) {
311:                    // Unpack invocation target exception
312:                    if (t instanceof  InvocationTargetException)
313:                        t = ((InvocationTargetException) t)
314:                                .getTargetException();
315:                    // BOException can be rethrown as is
316:                    if (t instanceof  BOException)
317:                        throw (BOException) t;
318:                    if (t instanceof  PSException)
319:                        throw new BOPersistenceServiceInvocationException(
320:                                "Caught exception while saving pending changes to domain entities",
321:                                (PSException) t);
322:                    if (t instanceof  NamingException)
323:                        throw new BONamingAndDirectoryServiceInvocationException(
324:                                "Caught exception while saving pending changes to domain entities",
325:                                (NamingException) t);
326:                    throw new BOException(
327:                            "Caught exception while saving pending changes to domain entities",
328:                            t);
329:                }
330:            }
331:
332:            /* Overridable method. Called when existing object enters being edited stage */
333:            protected void onBeginEdit() throws BOException {
334:            }
335:
336:            /* Encapsulates commit procedure */
337:            protected final void doCommit() throws BOException {
338:                try {
339:                    // Do commit on all entities first
340:                    for (Iterator lBOImplsIterator = mEntitiesInTransaction
341:                            .values().iterator(); lBOImplsIterator.hasNext();) {
342:                        BOObjectImpl lBOImpl = (BOObjectImpl) lBOImplsIterator
343:                                .next();
344:                        lBOImpl.doCommit();
345:                    }
346:                    // Work on domain object itself
347:                    switch (mState) {
348:                    case cStateBeingEdited:
349:                        onCommitUpdate();
350:                        mState = cStateReadOnly;
351:                        break;
352:                    default:
353:                        throw createInvalidOperationException();
354:                    }
355:                } finally {
356:                    // This method is final call in the transaction
357:                    cleanUpTransactionData();
358:                }
359:            }
360:
361:            /* Encapsulates commit action by this object */
362:            protected void onCommitUpdate() throws BOException {
363:                /* Do nothing by default */
364:            }
365:
366:            /* Encapsulates rollback procedure */
367:            protected final void doRollback() throws BOException {
368:                try {
369:                    // Do rollback on all entities first
370:                    for (Iterator lBOImplsIterator = mEntitiesInTransaction
371:                            .values().iterator(); lBOImplsIterator.hasNext();) {
372:                        BOObjectImpl lBOImpl = (BOObjectImpl) lBOImplsIterator
373:                                .next();
374:                        lBOImpl.doRollback();
375:                    }
376:                    // Work on domain object itself
377:                    switch (mState) {
378:                    case cStateBeingEdited:
379:                        onRollbackUpdate();
380:                        mState = cStateReadOnly;
381:                        break;
382:                    default:
383:                        throw createInvalidOperationException();
384:                    }
385:                } finally {
386:                    // This method is final call in the transaction
387:                    cleanUpTransactionData();
388:                }
389:            }
390:
391:            /* Encapsulates rollback action by this object */
392:            protected void onRollbackUpdate() throws BOException {
393:                /* Do nothing by default */
394:            }
395:
396:            // Helper. Checks if BO is setup and throws exception if it is not set
397:            private void checkValidState() throws BOException {
398:                if (mState == cStateNotSetUp)
399:                    throw new BOObjectNotInitialisedException();
400:            }
401:
402:            // Helper. Creates the invalid operation exception based on the object's state
403:            // Call it at the point when it is established that current state is not valid for the current operation
404:            public BOException createInvalidOperationException() {
405:                switch (mState) {
406:                case cStateNotSetUp:
407:                    return new BOObjectNotInitialisedException();
408:                case cStateReadOnly:
409:                    return new BOInvalidOperationForReadOnlyObjectDomainException();
410:                case cStateBeingEdited:
411:                    return new BOInvalidOperationForObjectDomainBeingEditedException();
412:                default:
413:                    return new BOObjectUnusableException();
414:                }
415:            }
416:
417:            // This object keeps details of outstanding persistence instruction
418:            // Persistence instfruction is one of create, update or delete entity
419:            // During transaction we keep accumulating these persistence instructions instead of
420:            // executing them on the spot. This gives us an opportunity to run batch operations prior to
421:            // transaction commit.
422:            private class PersistenceInstruction {
423:                public Class ImplClass = null;
424:                BOObjectImpl.BOImplMetaData ImplMetaData = null;
425:                public Method PersistenceMethod = null;
426:                public ArrayList InstancesList = new ArrayList();
427:            }
428:
429:            // This object keeps a list of outstanding persistence instructions
430:            // Note that each instruction may have a number of actual entities attached to it
431:            private class PersistenceInstructionList {
432:                private ArrayList mInstructionList = new ArrayList();
433:                private PersistenceInstruction mLastInstruction = null;
434:
435:                // Adds persistence instructon to the list. Collects things in batches
436:                public void addInstruction(Method pPersistenceMethod,
437:                        BOObjectImpl.BOImplMetaData pImplMetaData,
438:                        BOObjectImpl pBOImpl) {
439:                    if (mLastInstruction == null
440:                            || mLastInstruction.PersistenceMethod != pPersistenceMethod
441:                            || mLastInstruction.ImplClass != pBOImpl.getClass()) {
442:                        mInstructionList
443:                                .add(mLastInstruction = new PersistenceInstruction());
444:                        mLastInstruction.PersistenceMethod = pPersistenceMethod;
445:                        mLastInstruction.ImplClass = pBOImpl.getClass();
446:                        mLastInstruction.ImplMetaData = pImplMetaData;
447:                    }
448:                    mLastInstruction.InstancesList.add(pBOImpl);
449:                }
450:
451:                // Removes persistence instructon from the the list.
452:                public void removeInstruction(Method pPersistenceMethod,
453:                        BOObjectImpl.BOImplMetaData pImplMetaData,
454:                        BOObjectImpl pBOImpl) {
455:                    List lInstructionsToBeDeleted = null;
456:                    // Iterate through the instruction list and find this object
457:                    for (Iterator lInstructionIter = mInstructionList
458:                            .iterator(); lInstructionIter.hasNext();) {
459:                        PersistenceInstruction lInstruction = (PersistenceInstruction) lInstructionIter
460:                                .next();
461:                        if (lInstruction.PersistenceMethod
462:                                .equals(pPersistenceMethod)
463:                                && lInstruction.ImplClass.equals(pBOImpl
464:                                        .getClass())
465:                                && lInstruction.ImplMetaData
466:                                        .equals(pImplMetaData)
467:                                && lInstruction.InstancesList.remove(pBOImpl) == true) {
468:                            // We have in fact removed the istruction for this Bo
469:                            // If this instruction batch is empty - we need to remove the batch as well
470:                            if (mLastInstruction.InstancesList.isEmpty()) {
471:                                if (lInstructionsToBeDeleted == null)
472:                                    lInstructionsToBeDeleted = new ArrayList();
473:                                lInstructionsToBeDeleted.add(lInstruction);
474:                            }
475:                        }
476:                    }
477:                    // We may have some empty batches which should be deleted
478:                    if (lInstructionsToBeDeleted != null) {
479:                        // Remove all instructions that need to be removed
480:                        for (Iterator lInstructionIter = lInstructionsToBeDeleted
481:                                .iterator(); lInstructionIter.hasNext();) {
482:                            PersistenceInstruction lInstructionToBeDeleted = (PersistenceInstruction) lInstructionIter
483:                                    .next();
484:                            mInstructionList.remove(lInstructionToBeDeleted);
485:                        }
486:                        // We also may need to fix the last instruction reference (because we may have deleted it)
487:                        if (lInstructionsToBeDeleted.contains(mLastInstruction)) {
488:                            int lInstructionListSize = mInstructionList.size();
489:                            mLastInstruction = (PersistenceInstruction) (lInstructionListSize > 0 ? mInstructionList
490:                                    .get(lInstructionListSize - 1)
491:                                    : null);
492:                        }
493:                    }
494:                }
495:
496:                public int size() {
497:                    return mInstructionList.size();
498:                }
499:
500:                public void clear() {
501:                    mInstructionList.clear();
502:                    mLastInstruction = null;
503:                }
504:
505:                // This method will modify the list of persistence instructions after each save
506:                // it will remove delete instructions and change create instructions to update ones
507:                public void doAfterSave() {
508:                    // This will remove all delete instructions and change the create instructions to update ones
509:                    PersistenceInstruction[] lAllInstructions = (PersistenceInstruction[]) mInstructionList
510:                            .toArray(new PersistenceInstruction[mInstructionList
511:                                    .size()]);
512:                    mInstructionList.clear();
513:                    mLastInstruction = null;
514:                    for (int i = 0; i < lAllInstructions.length; i++) {
515:                        PersistenceInstruction lInstruction = lAllInstructions[i];
516:                        if (lInstruction.PersistenceMethod == lInstruction.ImplMetaData.DeleteMethod)
517:                            continue; // Deleted objects will not be saved again 
518:                        if (lInstruction.PersistenceMethod == lInstruction.ImplMetaData.UpdateMethod) {
519:                            // Basically we need to copy as is. But we will attempt to see if we can increase the batch
520:                            if (mLastInstruction != null
521:                                    && mLastInstruction.PersistenceMethod == lInstruction.PersistenceMethod
522:                                    && mLastInstruction.ImplClass == lInstruction.ImplClass) {
523:                                // Possibly because of change new - to existing we have now found that
524:                                // two batches can be amalgamated. Do it
525:                                mLastInstruction.InstancesList
526:                                        .addAll(lInstruction.InstancesList);
527:                            } else {
528:                                // Make a copy and mark this instruction as last
529:                                mInstructionList.add(lInstruction);
530:                                mLastInstruction = lInstruction;
531:                            }
532:                        } else if (lInstruction.PersistenceMethod == lInstruction.ImplMetaData.UpdateChangesToReferences) {
533:                            // This method just copied straight to the target 
534:                            mInstructionList.add(lInstruction);
535:                            mLastInstruction = lInstruction;
536:                        } else if (lInstruction.PersistenceMethod == lInstruction.ImplMetaData.CreateMethod) {
537:                            // This method becomes update method if there is one in the bo
538:                            // If there is no update method - this method is removed
539:                            if (lInstruction.ImplMetaData.UpdateMethod == null)
540:                                continue; // Nothing to add
541:                            lInstruction.PersistenceMethod = lInstruction.ImplMetaData.UpdateMethod; // Change create method to to update method
542:
543:                            // Basically we need to copy as is. But we will attempt to see if we can increase the batch
544:                            if (mLastInstruction != null
545:                                    && mLastInstruction.PersistenceMethod == lInstruction.PersistenceMethod
546:                                    && mLastInstruction.ImplClass == lInstruction.ImplClass) {
547:                                // Possibly because of change new - to existing we have now found that
548:                                // two batches can be amalgamated. Do it
549:                                mLastInstruction.InstancesList
550:                                        .addAll(lInstruction.InstancesList);
551:                            } else {
552:                                // Make a copy and mark this instruction as last
553:                                mInstructionList.add(lInstruction);
554:                                mLastInstruction = lInstruction;
555:                            }
556:                        }
557:                    }
558:                }
559:
560:                public Iterator iterator() {
561:                    return mInstructionList.iterator();
562:                }
563:            }
564:
565:            // This object keeps details of the change to association between entities
566:            // Change may be one of the following:
567:            // 1. Association creation. In this case Old values are nulls and new values are populated with instance ids
568:            // 2. Association removal. In this case Old values are populated with instance ids and new values are nulls
569:            // 3. Association edit. In this case Old values are populated with instance ids and new values are populated with instance ids
570:            private class EntityAssociationChangeDetails {
571:                // The unique identifier of the association
572:                public String AssociationTypeId;
573:                // The unique identifier of the aggregator entity instance as it was before this action
574:                // Equals null if association was not established before (i.e. this record is the record of creation of an association)
575:                public String OldAggregatorEntityInstance;
576:                // The unique identifier of the aggregatee entity instance as it was before this action
577:                // Equals null if association was not established before (i.e. this record is the record of creation of an association)
578:                public String OldAggregateeEntityInstance;
579:                // The unique identifier of the aggregator entity instance as it will be after this action
580:                // Equals null if association will not exist after (i.e. this record is the record of deletion of an association)
581:                public String NewAggregatorEntityInstance;
582:                // The unique identifier of the aggregatee entity instance as it will be after this action
583:                // Equals null if association will not exist after (i.e. this record is the record of deletion of an association)
584:                public String NewAggregateeEntityInstance;
585:            }
586:
587:            // This object keeps the list of changes to associations 
588:            private class EntityAssociationChangesList {
589:                // Details mapped by the association type id. The key is AssociationTypeId, the value is the list of actual association details
590:                private Map mDetailsByAssociationId = new HashMap();
591:
592:                // Details mapped by the entity. The key is EntityUri, the value is the list of actual association details
593:                private Map mDetailsByEntityInstanceId = new HashMap();
594:
595:                // Adds details about association in the list
596:                public void addAssociation(String pAssociationTypeId,
597:                        String pNewAggregatorEntityInstanceId,
598:                        String pNewAggregateeEntityInstanceId) {
599:                    EntityAssociationChangeDetails lEntityAssociationChangeDetails = new EntityAssociationChangeDetails();
600:                    lEntityAssociationChangeDetails.AssociationTypeId = pAssociationTypeId;
601:                    lEntityAssociationChangeDetails.NewAggregatorEntityInstance = pNewAggregatorEntityInstanceId;
602:                    lEntityAssociationChangeDetails.NewAggregateeEntityInstance = pNewAggregateeEntityInstanceId;
603:                    // Add to the list changes to of association
604:                    {
605:                        List lAssociationChanges = (List) mDetailsByAssociationId
606:                                .get(pAssociationTypeId);
607:                        if (lAssociationChanges == null)
608:                            mDetailsByAssociationId.put(pAssociationTypeId,
609:                                    lAssociationChanges = new ArrayList());
610:                        lAssociationChanges
611:                                .add(lEntityAssociationChangeDetails);
612:                    }
613:                    // Add to the list changes to the aggregator entity
614:                    {
615:                        List lEntityChanges = (List) mDetailsByEntityInstanceId
616:                                .get(pNewAggregatorEntityInstanceId);
617:                        if (lEntityChanges == null)
618:                            mDetailsByEntityInstanceId.put(
619:                                    pNewAggregatorEntityInstanceId,
620:                                    lEntityChanges = new ArrayList());
621:                        lEntityChanges.add(lEntityAssociationChangeDetails);
622:                    }
623:                    // Add to the list changes to the aggregatee entity
624:                    {
625:                        List lEntityChanges = (List) mDetailsByEntityInstanceId
626:                                .get(pNewAggregateeEntityInstanceId);
627:                        if (lEntityChanges == null)
628:                            mDetailsByEntityInstanceId.put(
629:                                    pNewAggregateeEntityInstanceId,
630:                                    lEntityChanges = new ArrayList());
631:                        lEntityChanges.add(lEntityAssociationChangeDetails);
632:                    }
633:                }
634:
635:                // Removes details about association from the list
636:                public void removeAssociationDetails(String pAssociationTypeId,
637:                        String pOldAggregatorEntityInstanceId,
638:                        String pOldAggregateeEntityInstanceId) {
639:                    EntityAssociationChangeDetails lEntityAssociationChangeDetails = new EntityAssociationChangeDetails();
640:                    lEntityAssociationChangeDetails.AssociationTypeId = pAssociationTypeId;
641:                    lEntityAssociationChangeDetails.OldAggregatorEntityInstance = pOldAggregatorEntityInstanceId;
642:                    lEntityAssociationChangeDetails.OldAggregateeEntityInstance = pOldAggregateeEntityInstanceId;
643:                    // Add to the list changes to of association
644:                    {
645:                        List lAssociationChanges = (List) mDetailsByAssociationId
646:                                .get(pAssociationTypeId);
647:                        if (lAssociationChanges == null)
648:                            mDetailsByAssociationId.put(pAssociationTypeId,
649:                                    lAssociationChanges = new ArrayList());
650:                        lAssociationChanges
651:                                .add(lEntityAssociationChangeDetails);
652:                    }
653:                    // Add to the list changes to the aggregator entity
654:                    {
655:                        List lEntityChanges = (List) mDetailsByEntityInstanceId
656:                                .get(pOldAggregatorEntityInstanceId);
657:                        if (lEntityChanges == null)
658:                            mDetailsByEntityInstanceId.put(
659:                                    pOldAggregatorEntityInstanceId,
660:                                    lEntityChanges = new ArrayList());
661:                        lEntityChanges.add(lEntityAssociationChangeDetails);
662:                    }
663:                    // Add to the list changes to the aggregatee entity
664:                    {
665:                        List lEntityChanges = (List) mDetailsByEntityInstanceId
666:                                .get(pOldAggregateeEntityInstanceId);
667:                        if (lEntityChanges == null)
668:                            mDetailsByEntityInstanceId.put(
669:                                    pOldAggregateeEntityInstanceId,
670:                                    lEntityChanges = new ArrayList());
671:                        lEntityChanges.add(lEntityAssociationChangeDetails);
672:                    }
673:                }
674:
675:                // Cleans up all contents of the list
676:                public void clear() {
677:                    mDetailsByAssociationId.clear();
678:                    mDetailsByEntityInstanceId.clear();
679:                }
680:            }
681:
682:            // This list contains details of all associations which have been changed in the current transaction
683:            private EntityAssociationChangesList mEntityAssociationInTransactionChangesList = new EntityAssociationChangesList();
684:
685:            // Set of entities in transaction. Used to keep track of entities
686:            // in need of roolback or commit processing
687:            private Map mEntitiesInTransaction = new HashMap();
688:            // Main list of transaction instructions - executed when commit command is issued
689:            private PersistenceInstructionList mMainInstructionsList = new PersistenceInstructionList();
690:            // Secondary list of transaction instructions - executed after main list
691:            private PersistenceInstructionList mDeferredInstructionsList = new PersistenceInstructionList();
692:
693:            // Registers entity for the creation before commit
694:            void registerEntityForCreate(BOObjectImpl pBOImpl)
695:                    throws BOException {
696:                // First obtain implementation's metadata
697:                BOObjectImpl.BOImplMetaData lBOImplMetaData = BOObjectImpl
698:                        .getBOImplMetaData(pBOImpl);
699:                if (lBOImplMetaData.CreateMethod == null)
700:                    throw new BOInvalidOperationForObjectException(
701:                            "Operation registerForCreate() is not valid for the entity. EntityType:"
702:                                    + pBOImpl.getEntityType());
703:                // Make sure that this domain is in transaction
704:                if (!isBeingEdited())
705:                    throw new BOObjectDomainNotInTransactionException();
706:                // Guard against duplicate modification instructions in the same transaction
707:                if (mEntitiesInTransaction.put(pBOImpl.getEntityUri(), pBOImpl) != null)
708:                    throw new BOObjectAlreadyInTransactionException();
709:                // Now add appropriate persistence instruction
710:                mMainInstructionsList.addInstruction(
711:                        lBOImplMetaData.CreateMethod, lBOImplMetaData, pBOImpl);
712:                // Add update many-to-many if this entity has one
713:                if (lBOImplMetaData.UpdateChangesToReferences != null)
714:                    mDeferredInstructionsList.addInstruction(
715:                            lBOImplMetaData.UpdateChangesToReferences,
716:                            lBOImplMetaData, pBOImpl);
717:                if (sLogger.isDebugEnabled())
718:                    sLogger
719:                            .debug("Creation of BO with InstanceId = '"
720:                                    + pBOImpl.getEntityInstanceId()
721:                                    + "' is added to deferred persistence instructions list. Current count of deferred persistence instructions is "
722:                                    + mMainInstructionsList.size());
723:            }
724:
725:            // Registers entity for the creation before commit
726:            void unregisterEntityForCreate(BOObjectImpl pBOImpl)
727:                    throws BOException {
728:                // First obtain implementation's metadata
729:                BOObjectImpl.BOImplMetaData lBOImplMetaData = BOObjectImpl
730:                        .getBOImplMetaData(pBOImpl);
731:                if (lBOImplMetaData.CreateMethod == null)
732:                    throw new BOInvalidOperationForObjectException(
733:                            "Operation unregisterForCreate() is not valid for the entity. EntityType:"
734:                                    + pBOImpl.getEntityType());
735:                // Make sure that this domain is in transaction
736:                if (!isBeingEdited())
737:                    throw new BOObjectDomainNotInTransactionException();
738:                // Guard against object which is not in transaction
739:                if (!mEntitiesInTransaction.containsKey(pBOImpl.getEntityUri()))
740:                    throw new BOObjectNotInTransactionException();
741:                // Now remove appropriate persistence instruction
742:                mMainInstructionsList.removeInstruction(
743:                        lBOImplMetaData.CreateMethod, lBOImplMetaData, pBOImpl);
744:                // Add update many-to-many if this entity has one
745:                if (lBOImplMetaData.UpdateChangesToReferences != null)
746:                    mDeferredInstructionsList.removeInstruction(
747:                            lBOImplMetaData.UpdateChangesToReferences,
748:                            lBOImplMetaData, pBOImpl);
749:                if (sLogger.isDebugEnabled())
750:                    sLogger
751:                            .debug("Creation of BO with InstanceId = '"
752:                                    + pBOImpl.getEntityInstanceId()
753:                                    + "' is removed from deferred persistence instructions list. Current count of deferred persistence instructions is "
754:                                    + mMainInstructionsList.size());
755:            }
756:
757:            // Registers object for the update before commit
758:            void registerEntityForUpdate(BOObjectImpl pBOImpl)
759:                    throws BOException {
760:                // First obtain implementation's metadata
761:                BOObjectImpl.BOImplMetaData lBOImplMetaData = BOObjectImpl
762:                        .getBOImplMetaData(pBOImpl);
763:                if (lBOImplMetaData.UpdateMethod == null)
764:                    throw new BOInvalidOperationForObjectException(
765:                            "Operation registerForUpdate() is not valid for the entity. EntityType:"
766:                                    + pBOImpl.getEntityType());
767:                // Make sure that this domain is in transaction
768:                if (!isBeingEdited())
769:                    throw new BOObjectDomainNotInTransactionException();
770:                // Guard against duplicate modification instructions in the same transaction
771:                if (mEntitiesInTransaction.put(pBOImpl.getEntityUri(), pBOImpl) != null)
772:                    throw new BOObjectAlreadyInTransactionException();
773:                // Now add appropriate persistence instruction
774:                mMainInstructionsList.addInstruction(
775:                        lBOImplMetaData.UpdateMethod, lBOImplMetaData, pBOImpl);
776:                // Add update many-to-many if this entity has one
777:                if (lBOImplMetaData.UpdateChangesToReferences != null)
778:                    mDeferredInstructionsList.addInstruction(
779:                            lBOImplMetaData.UpdateChangesToReferences,
780:                            lBOImplMetaData, pBOImpl);
781:                if (sLogger.isDebugEnabled())
782:                    sLogger
783:                            .debug("Update of BO with InstanceId = '"
784:                                    + pBOImpl.getEntityInstanceId()
785:                                    + "' is added to deferred persistence instructions list. Current count of deferred persistence instructions is "
786:                                    + mMainInstructionsList.size());
787:            }
788:
789:            // Registers object for the delete before commit
790:            void registerEntityForDelete(BOObjectImpl pBOImpl)
791:                    throws BOException {
792:                // First obtain implementation's metadata
793:                BOObjectImpl.BOImplMetaData lBOImplMetaData = BOObjectImpl
794:                        .getBOImplMetaData(pBOImpl);
795:                if (lBOImplMetaData.DeleteMethod == null)
796:                    throw new BOInvalidOperationForObjectException(
797:                            "Operation registerForDelete() is not valid for the entity. EntityType:"
798:                                    + pBOImpl.getEntityType());
799:                // Make sure that this domain is in transaction
800:                if (!isBeingEdited())
801:                    throw new BOObjectDomainNotInTransactionException();
802:                // Guard against duplicate modification instructions in the same transaction
803:                if (mEntitiesInTransaction.put(pBOImpl.getEntityUri(), pBOImpl) != null)
804:                    throw new BOObjectAlreadyInTransactionException();
805:                // Now add appropriate persistence instruction
806:                mMainInstructionsList.addInstruction(
807:                        lBOImplMetaData.DeleteMethod, lBOImplMetaData, pBOImpl);
808:                if (sLogger.isDebugEnabled())
809:                    sLogger
810:                            .debug("Deletion of BO with InstanceId = '"
811:                                    + pBOImpl.getEntityInstanceId()
812:                                    + "' is added to deferred persistence instructions list. Current count of deferred persistence instructions is "
813:                                    + mMainInstructionsList.size());
814:            }
815:
816:            // Unregisters object for the delete before commit
817:            void unregisterEntityForDelete(BOObjectImpl pBOImpl)
818:                    throws BOException {
819:                // First obtain implementation's metadata
820:                BOObjectImpl.BOImplMetaData lBOImplMetaData = BOObjectImpl
821:                        .getBOImplMetaData(pBOImpl);
822:                if (lBOImplMetaData.DeleteMethod == null)
823:                    throw new BOInvalidOperationForObjectException(
824:                            "Operation unregisterForDelete() is not valid for the entity. EntityType:"
825:                                    + pBOImpl.getEntityType());
826:                // Make sure that this domain is in transaction
827:                if (!isBeingEdited())
828:                    throw new BOObjectDomainNotInTransactionException();
829:                // Guard against object which is not in transaction
830:                if (!mEntitiesInTransaction.containsKey(pBOImpl.getEntityUri()))
831:                    throw new BOObjectNotInTransactionException();
832:                // Now add appropriate persistence instruction
833:                mMainInstructionsList.removeInstruction(
834:                        lBOImplMetaData.DeleteMethod, lBOImplMetaData, pBOImpl);
835:                if (sLogger.isDebugEnabled())
836:                    sLogger
837:                            .debug("Deletion of BO with InstanceId = '"
838:                                    + pBOImpl.getEntityInstanceId()
839:                                    + "' is removed from deferred persistence instructions list. Current count of deferred persistence instructions is "
840:                                    + mMainInstructionsList.size());
841:            }
842:
843:            // This helper cleans up the data about transacton
844:            private void cleanUpTransactionData() {
845:                mEntitiesInTransaction.clear();
846:                mMainInstructionsList.clear();
847:                mDeferredInstructionsList.clear();
848:                mEntityAssociationInTransactionChangesList.clear();
849:                if (sLogger.isDebugEnabled())
850:                    sLogger
851:                            .debug("Deferred persistence instructions list is cleared.");
852:            }
853:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.