Source Code Cross Referenced for DetachManager.java in  » Database-ORM » openjpa » org » apache » openjpa » kernel » 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 » Database ORM » openjpa » org.apache.openjpa.kernel 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         * Licensed to the Apache Software Foundation (ASF) under one
003:         * or more contributor license agreements.  See the NOTICE file
004:         * distributed with this work for additional information
005:         * regarding copyright ownership.  The ASF licenses this file
006:         * to you under the Apache License, Version 2.0 (the
007:         * "License"); you may not use this file except in compliance
008:         * with the License.  You may obtain a copy of the License at
009:         *
010:         * http://www.apache.org/licenses/LICENSE-2.0
011:         *
012:         * Unless required by applicable law or agreed to in writing,
013:         * software distributed under the License is distributed on an
014:         * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015:         * KIND, either express or implied.  See the License for the
016:         * specific language governing permissions and limitations
017:         * under the License.    
018:         */
019:        package org.apache.openjpa.kernel;
020:
021:        import java.io.IOException;
022:        import java.io.ObjectOutput;
023:        import java.lang.reflect.Array;
024:        import java.util.ArrayList;
025:        import java.util.BitSet;
026:        import java.util.Calendar;
027:        import java.util.Collection;
028:        import java.util.Collections;
029:        import java.util.Comparator;
030:        import java.util.Date;
031:        import java.util.Iterator;
032:        import java.util.LinkedList;
033:        import java.util.List;
034:        import java.util.Map;
035:
036:        import org.apache.commons.collections.map.IdentityMap;
037:        import org.apache.openjpa.conf.DetachOptions;
038:        import org.apache.openjpa.enhance.PersistenceCapable;
039:        import org.apache.openjpa.event.CallbackModes;
040:        import org.apache.openjpa.event.LifecycleEvent;
041:        import org.apache.openjpa.lib.util.Localizer;
042:        import org.apache.openjpa.meta.ClassMetaData;
043:        import org.apache.openjpa.meta.FieldMetaData;
044:        import org.apache.openjpa.meta.JavaTypes;
045:        import org.apache.openjpa.util.CallbackException;
046:        import org.apache.openjpa.util.ObjectNotFoundException;
047:        import org.apache.openjpa.util.Proxy;
048:        import org.apache.openjpa.util.ProxyManager;
049:        import org.apache.openjpa.util.UserException;
050:
051:        /**
052:         * Handles detaching instances.
053:         *
054:         * @author Marc Prud'hommeaux
055:         * @nojavadoc
056:         */
057:        public class DetachManager implements  DetachState {
058:
059:            private static Localizer _loc = Localizer
060:                    .forPackage(DetachManager.class);
061:
062:            private final BrokerImpl _broker;
063:            private final boolean _copy;
064:            private final boolean _full;
065:            private final ProxyManager _proxy;
066:            private final DetachOptions _opts;
067:            private final OpCallbacks _call;
068:            private final boolean _failFast;
069:            private boolean _flushed = false;
070:
071:            // if we're not detaching full, we need to track all detached objects;
072:            // if we are, then we use a special field manager for more efficient
073:            // detachment than the standard one
074:            private final IdentityMap _detached;
075:            private final DetachFieldManager _fullFM;
076:
077:            /**
078:             * Used to prepare a detachable instance that does not externalize
079:             * detached state.
080:             */
081:            static boolean preSerialize(StateManagerImpl sm) {
082:                if (!sm.isPersistent())
083:                    return false;
084:
085:                flushDirty(sm);
086:
087:                ClassMetaData meta = sm.getMetaData();
088:                boolean setState = meta.getDetachedState() != null
089:                        && !ClassMetaData.SYNTHETIC.equals(meta
090:                                .getDetachedState());
091:                BitSet idxs = (setState) ? new BitSet(meta.getFields().length)
092:                        : null;
093:                preDetach(sm.getBroker(), sm, idxs);
094:
095:                if (setState) {
096:                    sm.getPersistenceCapable().pcSetDetachedState(
097:                            getDetachedState(sm, idxs));
098:                    return false; // don't null state
099:                }
100:                return true;
101:            }
102:
103:            /**
104:             * Used by classes that externalize detached state.
105:             *
106:             * @return whether to use a detached state manager
107:             */
108:            static boolean writeDetachedState(StateManagerImpl sm,
109:                    ObjectOutput out, BitSet idxs) throws IOException {
110:                if (!sm.isPersistent()) {
111:                    out.writeObject(null); // state
112:                    out.writeObject(null); // sm
113:                    return false;
114:                }
115:
116:                // dirty state causes flush
117:                flushDirty(sm);
118:
119:                Broker broker = sm.getBroker();
120:                preDetach(broker, sm, idxs);
121:
122:                // write detached state object and state manager
123:                DetachOptions opts = broker.getConfiguration()
124:                        .getDetachStateInstance();
125:                if (!opts.getDetachedStateManager()
126:                        || !useDetachedStateManager(sm, opts)) {
127:                    out.writeObject(getDetachedState(sm, idxs));
128:                    out.writeObject(null);
129:                    return false;
130:                }
131:                out.writeObject(null);
132:                out.writeObject(new DetachedStateManager(sm
133:                        .getPersistenceCapable(), sm, idxs, opts
134:                        .getAccessUnloaded(), broker.getMultithreaded()));
135:                return true;
136:            }
137:
138:            /**
139:             * Ready the object for detachment, including loading the fields to be
140:             * detached and updating version information.
141:             *
142:             * @param idxs the indexes of fields to detach will be set as a side
143:             * effect of this method
144:             */
145:            private static void preDetach(Broker broker, StateManagerImpl sm,
146:                    BitSet idxs) {
147:                // make sure the existing object has the right fields fetched; call
148:                // even if using currently-loaded fields for detach to make sure
149:                // version is set
150:                int detachMode = broker.getDetachState();
151:                int loadMode = StateManagerImpl.LOAD_FGS;
152:                BitSet exclude = null;
153:                if (detachMode == DETACH_LOADED)
154:                    exclude = StoreContext.EXCLUDE_ALL;
155:                else if (detachMode == DETACH_ALL)
156:                    loadMode = StateManagerImpl.LOAD_ALL;
157:                try {
158:                    sm.load(broker.getFetchConfiguration(), loadMode, exclude,
159:                            null, false);
160:                } catch (ObjectNotFoundException onfe) {
161:                    // consume the exception
162:                }
163:
164:                // create bitset of fields to detach; if mode is all we can use
165:                // currently loaded bitset clone, since we know all fields are loaded
166:                if (idxs != null) {
167:                    if (detachMode == DETACH_FETCH_GROUPS)
168:                        setFetchGroupFields(broker, sm, idxs);
169:                    else
170:                        idxs.or(sm.getLoaded());
171:
172:                    // clear lrs fields
173:                    FieldMetaData[] fmds = sm.getMetaData().getFields();
174:                    for (int i = 0; i < fmds.length; i++)
175:                        if (fmds[i].isLRS())
176:                            idxs.clear(i);
177:                }
178:            }
179:
180:            /**
181:             * Generate the detached state for the given instance.
182:             */
183:            private static Object getDetachedState(StateManagerImpl sm,
184:                    BitSet fields) {
185:                // if datastore, store id in first element
186:                int offset = (sm.getMetaData().getIdentityType() == ClassMetaData.ID_DATASTORE) ? 1
187:                        : 0;
188:
189:                // make version state array one larger for new instances; marks new
190:                // instances without affecting serialization size much
191:                Object[] state;
192:                if (sm.isNew())
193:                    state = new Object[3 + offset];
194:                else
195:                    state = new Object[2 + offset];
196:
197:                if (offset > 0) {
198:                    Object id;
199:                    if (sm.isEmbedded() || sm.getObjectId() == null)
200:                        id = sm.getId();
201:                    else
202:                        id = sm.getObjectId();
203:                    state[0] = id.toString();
204:                }
205:                state[offset] = sm.getVersion();
206:                state[offset + 1] = fields;
207:                return state;
208:            }
209:
210:            /**
211:             * Flush or invoke pre-store callbacks on the given broker if
212:             * needed. Return true if flushed/stored, false otherwise.
213:             */
214:            private static boolean flushDirty(StateManagerImpl sm) {
215:                if (!sm.isDirty() || !sm.getBroker().isActive())
216:                    return false;
217:
218:                // only flush if there are actually any dirty non-flushed fields
219:                BitSet dirtyFields = sm.getDirty();
220:                BitSet flushedFields = sm.getFlushed();
221:                for (int i = 0; i < dirtyFields.size(); i++) {
222:                    if (dirtyFields.get(i) && !flushedFields.get(i)) {
223:                        if (sm.getBroker().getRollbackOnly())
224:                            sm.getBroker().preFlush();
225:                        else
226:                            sm.getBroker().flush();
227:                        return true;
228:                    }
229:                }
230:                return false;
231:            }
232:
233:            /**
234:             * Create a bit set for the fields in the current fetch groups.
235:             */
236:            private static void setFetchGroupFields(Broker broker,
237:                    StateManagerImpl sm, BitSet idxs) {
238:                FetchConfiguration fetch = broker.getFetchConfiguration();
239:                FieldMetaData[] fmds = sm.getMetaData().getFields();
240:                for (int i = 0; i < fmds.length; i++) {
241:                    if (fmds[i].isPrimaryKey()
242:                            || fetch.requiresFetch(fmds[i]) != FetchConfiguration.FETCH_NONE)
243:                        idxs.set(i);
244:                }
245:            }
246:
247:            /**
248:             * Constructor.
249:             *
250:             * @param broker owning broker
251:             * @param full whether the entire broker cache is being detached; if
252:             * this is the case, we assume the broker has already
253:             * flushed if needed, and that we're detaching in-place
254:             */
255:            public DetachManager(BrokerImpl broker, boolean full,
256:                    OpCallbacks call) {
257:                _broker = broker;
258:                _proxy = broker.getConfiguration().getProxyManagerInstance();
259:                _opts = broker.getConfiguration().getDetachStateInstance();
260:                _copy = !full;
261:                _flushed = full;
262:                _call = call;
263:                _failFast = (broker.getConfiguration()
264:                        .getMetaDataRepositoryInstance().getMetaDataFactory()
265:                        .getDefaults().getCallbackMode() & CallbackModes.CALLBACK_FAIL_FAST) != 0;
266:
267:                // we can only rely on our "all" shortcuts if we know we won't be
268:                // loading any more data
269:                _full = full
270:                        && broker.getDetachState() == DetachState.DETACH_LOADED;
271:                if (_full) {
272:                    _detached = null;
273:                    _fullFM = new DetachFieldManager();
274:                } else {
275:                    _detached = new IdentityMap();
276:                    _fullFM = null;
277:                }
278:            }
279:
280:            /**
281:             * Return a detached version of the given instance.
282:             */
283:            public Object detach(Object toDetach) {
284:                List exceps = null;
285:                try {
286:                    return detachInternal(toDetach);
287:                } catch (CallbackException ce) {
288:                    exceps = new ArrayList(1);
289:                    exceps.add(ce);
290:                    return null; // won't be reached as exception will be rethrown
291:                } finally {
292:                    if (exceps == null || !_failFast)
293:                        exceps = invokeAfterDetach(Collections
294:                                .singleton(toDetach), exceps);
295:                    if (_detached != null)
296:                        _detached.clear();
297:                    throwExceptions(exceps);
298:                }
299:            }
300:
301:            /**
302:             * Return detached versions of all the given instances. If not copying,
303:             * null will be returned.
304:             */
305:            public Object[] detachAll(Collection instances) {
306:                List exceps = null;
307:                List detached = null;
308:                if (_copy)
309:                    detached = new ArrayList(instances.size());
310:
311:                boolean failFast = false;
312:                try {
313:                    Object detach;
314:                    for (Iterator itr = instances.iterator(); itr.hasNext();) {
315:                        detach = detachInternal(itr.next());
316:                        if (_copy)
317:                            detached.add(detach);
318:                    }
319:                } catch (RuntimeException re) {
320:                    if (re instanceof  CallbackException && _failFast)
321:                        failFast = true;
322:                    exceps = add(exceps, re);
323:                } finally {
324:                    if (!failFast)
325:                        exceps = invokeAfterDetach(instances, exceps);
326:                    if (_detached != null)
327:                        _detached.clear();
328:                }
329:                throwExceptions(exceps);
330:
331:                if (_copy)
332:                    return detached.toArray();
333:                return null;
334:            }
335:
336:            /**
337:             * Invoke postDetach() on any detached instances that implement
338:             * PostDetachCallback. This will be done after the entire graph has
339:             * been detached. This method has the side-effect of also clearing
340:             * out the map of all detached instances.
341:             */
342:            private List invokeAfterDetach(Collection objs, List exceps) {
343:                Iterator itr = (_full) ? objs.iterator() : _detached.entrySet()
344:                        .iterator();
345:
346:                Object orig, detached;
347:                Map.Entry entry;
348:                while (itr.hasNext()) {
349:                    if (_full) {
350:                        orig = itr.next();
351:                        detached = orig;
352:                    } else {
353:                        entry = (Map.Entry) itr.next();
354:                        orig = entry.getKey();
355:                        detached = entry.getValue();
356:                    }
357:
358:                    StateManagerImpl sm = _broker.getStateManagerImpl(orig,
359:                            true);
360:                    try {
361:                        if (sm != null)
362:                            _broker
363:                                    .fireLifecycleEvent(detached, orig, sm
364:                                            .getMetaData(),
365:                                            LifecycleEvent.AFTER_DETACH);
366:                    } catch (CallbackException ce) {
367:                        exceps = add(exceps, ce);
368:                        if (_failFast)
369:                            break; // don't continue processing
370:                    }
371:                }
372:                return exceps;
373:            }
374:
375:            /**
376:             * Add an exception to the list.
377:             */
378:            private List add(List exceps, RuntimeException re) {
379:                if (exceps == null)
380:                    exceps = new LinkedList();
381:                exceps.add(re);
382:                return exceps;
383:            }
384:
385:            /**
386:             * Throw all gathered exceptions.
387:             */
388:            private void throwExceptions(List exceps) {
389:                if (exceps == null)
390:                    return;
391:
392:                if (exceps.size() == 1)
393:                    throw (RuntimeException) exceps.get(0);
394:                throw new UserException(_loc.get("nested-exceps"))
395:                        .setNestedThrowables((Throwable[]) exceps
396:                                .toArray(new Throwable[exceps.size()]));
397:            }
398:
399:            /**
400:             * Detach.
401:             */
402:            private Object detachInternal(Object toDetach) {
403:                if (toDetach == null)
404:                    return null;
405:
406:                // already detached?
407:                if (_detached != null) {
408:                    Object detached = _detached.get(toDetach);
409:                    if (detached != null)
410:                        return detached;
411:                }
412:
413:                StateManagerImpl sm = _broker.getStateManagerImpl(toDetach,
414:                        true);
415:                if (_call != null
416:                        && (_call.processArgument(OpCallbacks.OP_DETACH,
417:                                toDetach, sm) & OpCallbacks.ACT_RUN) == 0)
418:                    return toDetach;
419:                if (sm == null)
420:                    return toDetach;
421:
422:                // Call PreDetach first as we can't tell if the new system
423:                // fired an event or just did not fail.
424:                _broker.fireLifecycleEvent(toDetach, null, sm.getMetaData(),
425:                        LifecycleEvent.BEFORE_DETACH);
426:
427:                // any dirty instances cause a flush to occur
428:                _flushed = _flushed || flushDirty(sm);
429:                BitSet fields = new BitSet();
430:                preDetach(_broker, sm, fields);
431:
432:                // create and store new object before copy to avoid endless recursion
433:                PersistenceCapable pc = sm.getPersistenceCapable();
434:                PersistenceCapable detachedPC;
435:                if (_copy)
436:                    detachedPC = pc.pcNewInstance(null, true);
437:                else
438:                    detachedPC = pc;
439:                if (_detached != null)
440:                    _detached.put(toDetach, detachedPC);
441:
442:                // detach fields and set detached variables
443:                DetachedStateManager detSM = null;
444:                if (_opts.getDetachedStateManager()
445:                        && useDetachedStateManager(sm, _opts))
446:                    detSM = new DetachedStateManager(detachedPC, sm, fields,
447:                            _opts.getAccessUnloaded(), _broker
448:                                    .getMultithreaded());
449:                if (_full) {
450:                    _fullFM.setStateManager(sm);
451:                    _fullFM.detachVersion();
452:                    _fullFM.reproxy(detSM);
453:                    _fullFM.setStateManager(null);
454:                } else {
455:                    InstanceDetachFieldManager fm = new InstanceDetachFieldManager(
456:                            detachedPC, detSM);
457:                    fm.setStateManager(sm);
458:                    fm.detachFields(fields);
459:                }
460:
461:                if (!Boolean.FALSE.equals(sm.getMetaData().usesDetachedState()))
462:                    detachedPC.pcSetDetachedState(getDetachedState(sm, fields));
463:                if (!_copy)
464:                    sm.release(false, !_copy);
465:                if (detSM != null)
466:                    detachedPC.pcReplaceStateManager(detSM);
467:                return detachedPC;
468:            }
469:
470:            private static boolean useDetachedStateManager(StateManagerImpl sm,
471:                    DetachOptions opts) {
472:                ClassMetaData meta = sm.getMetaData();
473:                return !Boolean.FALSE.equals(meta.usesDetachedState())
474:                        && ClassMetaData.SYNTHETIC.equals(meta
475:                                .getDetachedState())
476:                        && opts.getDetachedStateManager();
477:            }
478:
479:            /**
480:             * Base detach field manager.
481:             */
482:            private static class DetachFieldManager extends
483:                    TransferFieldManager {
484:
485:                protected StateManagerImpl sm;
486:
487:                /**
488:                 * Set the source state manager.
489:                 */
490:                public void setStateManager(StateManagerImpl sm) {
491:                    this .sm = sm;
492:                }
493:
494:                /**
495:                 * Transfer the current version object from the state manager to the
496:                 * detached instance.
497:                 */
498:                public void detachVersion() {
499:                    FieldMetaData fmd = sm.getMetaData().getVersionField();
500:                    if (fmd == null)
501:                        return;
502:
503:                    Object val = JavaTypes.convert(sm.getVersion(), fmd
504:                            .getTypeCode());
505:                    val = fmd.getFieldValue(val, sm.getBroker());
506:                    switch (fmd.getDeclaredTypeCode()) {
507:                    case JavaTypes.LONG:
508:                    case JavaTypes.SHORT:
509:                    case JavaTypes.INT:
510:                    case JavaTypes.BYTE:
511:                        longval = (val == null) ? 0L : ((Number) val)
512:                                .longValue();
513:                        break;
514:                    case JavaTypes.DOUBLE:
515:                    case JavaTypes.FLOAT:
516:                        dblval = (val == null) ? 0D : ((Number) val)
517:                                .doubleValue();
518:                        break;
519:                    default:
520:                        objval = val;
521:                    }
522:                    sm.replaceField(getDetachedPersistenceCapable(), this , fmd
523:                            .getIndex());
524:                }
525:
526:                /**
527:                 * Unproxies second class object fields.
528:                 */
529:                public void reproxy(DetachedStateManager dsm) {
530:                    FieldMetaData[] fmds = sm.getMetaData().getFields();
531:                    for (int i = 0; i < fmds.length; i++) {
532:                        switch (fmds[i].getDeclaredTypeCode()) {
533:                        case JavaTypes.COLLECTION:
534:                        case JavaTypes.MAP:
535:                            // lrs proxies not detached
536:                            if (fmds[i].isLRS()) {
537:                                objval = null;
538:                                sm.replaceField(
539:                                        getDetachedPersistenceCapable(), this ,
540:                                        i);
541:                                break;
542:                            }
543:                            // no break
544:                        case JavaTypes.CALENDAR:
545:                        case JavaTypes.DATE:
546:                        case JavaTypes.OBJECT:
547:                            sm.provideField(getDetachedPersistenceCapable(),
548:                                    this , i);
549:                            if (objval instanceof  Proxy) {
550:                                Proxy proxy = (Proxy) objval;
551:                                if (proxy.getChangeTracker() != null)
552:                                    proxy.getChangeTracker().stopTracking();
553:                                proxy.setOwner(dsm, (dsm == null) ? -1 : i);
554:                            }
555:                        }
556:                    }
557:                    clear();
558:                }
559:
560:                /**
561:                 * Return the instance being detached.
562:                 */
563:                protected PersistenceCapable getDetachedPersistenceCapable() {
564:                    return sm.getPersistenceCapable();
565:                }
566:            }
567:
568:            /**
569:             * FieldManager that can copy all the fields from one
570:             * PersistenceCapable instance to another. One of the
571:             * instances must be managed by a StateManager, and the
572:             * other must be unmanaged.
573:             *
574:             * @author Marc Prud'hommeaux
575:             */
576:            private class InstanceDetachFieldManager extends DetachFieldManager {
577:
578:                private final PersistenceCapable _to;
579:                private final DetachedStateManager _detSM;
580:
581:                /**
582:                 * Constructor. Supply instance to to copy to.
583:                 */
584:                public InstanceDetachFieldManager(PersistenceCapable to,
585:                        DetachedStateManager detSM) {
586:                    _to = to;
587:                    _detSM = detSM;
588:                }
589:
590:                protected PersistenceCapable getDetachedPersistenceCapable() {
591:                    return _to;
592:                }
593:
594:                /**
595:                 * Detach the fields of the state manager given on construction to
596:                 * the persistence capable given on construction.
597:                 * Only the fields in the given bit set will be copied.
598:                 */
599:                public void detachFields(BitSet fgfields) {
600:                    PersistenceCapable from = sm.getPersistenceCapable();
601:                    FieldMetaData[] pks = sm.getMetaData()
602:                            .getPrimaryKeyFields();
603:                    FieldMetaData[] fmds = sm.getMetaData().getFields();
604:
605:                    if (_copy)
606:                        _to.pcReplaceStateManager(sm);
607:                    try {
608:                        // we start with pk fields: objects might rely on pk fields for
609:                        // equals and hashCode methods, and this ensures that pk fields
610:                        // are set properly if we return any partially-detached objects
611:                        // due to reentrant calls when traversing relations
612:                        for (int i = 0; i < pks.length; i++)
613:                            detachField(from, pks[i].getIndex(), true);
614:                        detachVersion();
615:                        for (int i = 0; i < fmds.length; i++)
616:                            if (!fmds[i].isPrimaryKey() && !fmds[i].isVersion())
617:                                detachField(from, i, fgfields.get(i));
618:                    } finally {
619:                        // clear the StateManager from the target object
620:                        if (_copy)
621:                            _to.pcReplaceStateManager(null);
622:                    }
623:                }
624:
625:                /**
626:                 * Detach (or clear) the given field index.
627:                 */
628:                private void detachField(PersistenceCapable from, int i,
629:                        boolean fg) {
630:                    // tell the state manager to provide the fields from the source to
631:                    // this field manager, which will then replace the field with a
632:                    // detached version
633:                    if (fg)
634:                        sm.provideField(from, this , i);
635:                    else if (!_copy) {
636:                        // if not copying and field should not be detached, clear it
637:                        clear();
638:                        sm.replaceField(_to, this , i);
639:                    }
640:                }
641:
642:                public void storeBooleanField(int field, boolean curVal) {
643:                    super .storeBooleanField(field, curVal);
644:                    sm.replaceField(_to, this , field);
645:                }
646:
647:                public void storeByteField(int field, byte curVal) {
648:                    super .storeByteField(field, curVal);
649:                    sm.replaceField(_to, this , field);
650:                }
651:
652:                public void storeCharField(int field, char curVal) {
653:                    super .storeCharField(field, curVal);
654:                    sm.replaceField(_to, this , field);
655:                }
656:
657:                public void storeDoubleField(int field, double curVal) {
658:                    super .storeDoubleField(field, curVal);
659:                    sm.replaceField(_to, this , field);
660:                }
661:
662:                public void storeFloatField(int field, float curVal) {
663:                    super .storeFloatField(field, curVal);
664:                    sm.replaceField(_to, this , field);
665:                }
666:
667:                public void storeIntField(int field, int curVal) {
668:                    super .storeIntField(field, curVal);
669:                    sm.replaceField(_to, this , field);
670:                }
671:
672:                public void storeLongField(int field, long curVal) {
673:                    super .storeLongField(field, curVal);
674:                    sm.replaceField(_to, this , field);
675:                }
676:
677:                public void storeShortField(int field, short curVal) {
678:                    super .storeShortField(field, curVal);
679:                    sm.replaceField(_to, this , field);
680:                }
681:
682:                public void storeStringField(int field, String curVal) {
683:                    super .storeStringField(field, curVal);
684:                    sm.replaceField(_to, this , field);
685:                }
686:
687:                public void storeObjectField(int field, Object curVal) {
688:                    super .storeObjectField(field, detachField(curVal, field));
689:                    sm.replaceField(_to, this , field);
690:                }
691:
692:                /**
693:                 * Set the owner of the field's proxy to the detached state manager.
694:                 */
695:                private Object reproxy(Object obj, int field) {
696:                    if (obj != null && _detSM != null && obj instanceof  Proxy)
697:                        ((Proxy) obj).setOwner(_detSM, field);
698:                    return obj;
699:                }
700:
701:                /**
702:                 * Detach the given value if needed.
703:                 */
704:                private Object detachField(Object curVal, int field) {
705:                    if (curVal == null)
706:                        return null;
707:
708:                    FieldMetaData fmd = sm.getMetaData().getField(field);
709:                    Object newVal = null;
710:                    switch (fmd.getDeclaredTypeCode()) {
711:                    case JavaTypes.ARRAY:
712:                        if (_copy)
713:                            newVal = _proxy.copyArray(curVal);
714:                        else
715:                            newVal = curVal;
716:                        detachArray(newVal, fmd);
717:                        return newVal;
718:                    case JavaTypes.COLLECTION:
719:                        if (_copy) {
720:                            if (_detSM != null) {
721:                                newVal = _proxy
722:                                        .newCollectionProxy(
723:                                                fmd.getProxyType(),
724:                                                fmd.getElement()
725:                                                        .getDeclaredType(),
726:                                                fmd.getInitializer() instanceof  Comparator ? (Comparator) fmd
727:                                                        .getInitializer()
728:                                                        : null);
729:                                ((Collection) newVal)
730:                                        .addAll((Collection) curVal);
731:                            } else
732:                                newVal = _proxy
733:                                        .copyCollection((Collection) curVal);
734:                        } else
735:                            newVal = curVal;
736:                        detachCollection((Collection) newVal,
737:                                (Collection) curVal, fmd);
738:                        return reproxy(newVal, field);
739:                    case JavaTypes.MAP:
740:                        if (_copy) {
741:                            if (_detSM != null) {
742:                                newVal = _proxy
743:                                        .newMapProxy(
744:                                                fmd.getProxyType(),
745:                                                fmd.getKey().getDeclaredType(),
746:                                                fmd.getElement()
747:                                                        .getDeclaredType(),
748:                                                fmd.getInitializer() instanceof  Comparator ? (Comparator) fmd
749:                                                        .getInitializer()
750:                                                        : null);
751:                                ((Map) newVal).putAll((Map) curVal);
752:                            } else
753:                                newVal = _proxy.copyMap((Map) curVal);
754:                        } else
755:                            newVal = curVal;
756:                        detachMap((Map) newVal, (Map) curVal, fmd);
757:                        return reproxy(newVal, field);
758:                    case JavaTypes.CALENDAR:
759:                        newVal = (_copy) ? _proxy
760:                                .copyCalendar((Calendar) curVal) : curVal;
761:                        return reproxy(newVal, field);
762:                    case JavaTypes.DATE:
763:                        newVal = (_copy) ? _proxy.copyDate((Date) curVal)
764:                                : curVal;
765:                        return reproxy(newVal, field);
766:                    case JavaTypes.OBJECT:
767:                        if (_copy)
768:                            newVal = _proxy.copyCustom(curVal);
769:                        return reproxy((newVal == null) ? curVal : newVal,
770:                                field);
771:                    case JavaTypes.PC:
772:                    case JavaTypes.PC_UNTYPED:
773:                        return detachInternal(curVal);
774:                    default:
775:                        return curVal;
776:                    }
777:                }
778:
779:                /**
780:                 * Make sure all the values in the given array are detached.
781:                 */
782:                private void detachArray(Object array, FieldMetaData fmd) {
783:                    if (!fmd.getElement().isDeclaredTypePC())
784:                        return;
785:
786:                    int len = Array.getLength(array);
787:                    for (int i = 0; i < len; i++)
788:                        Array
789:                                .set(array, i, detachInternal(Array.get(array,
790:                                        i)));
791:                }
792:
793:                /**
794:                 * Make sure all the values in the given collection are detached.
795:                 */
796:                private void detachCollection(Collection coll, Collection orig,
797:                        FieldMetaData fmd) {
798:                    // coll can be null if not copyable
799:                    if (_copy && coll == null)
800:                        throw new UserException(_loc.get("not-copyable", fmd));
801:                    if (!fmd.getElement().isDeclaredTypePC())
802:                        return;
803:
804:                    // unfortunately we have to clear the original and re-add to copy
805:                    if (_copy)
806:                        coll.clear();
807:                    Object detached;
808:                    for (Iterator itr = orig.iterator(); itr.hasNext();) {
809:                        detached = detachInternal(itr.next());
810:                        if (_copy)
811:                            coll.add(detached);
812:                    }
813:                }
814:
815:                /**
816:                 * Make sure all the values in the given map are detached.
817:                 */
818:                private void detachMap(Map map, Map orig, FieldMetaData fmd) {
819:                    // map can be null if not copyable
820:                    if (_copy && map == null)
821:                        throw new UserException(_loc.get("not-copyable", fmd));
822:                    boolean keyPC = fmd.getKey().isDeclaredTypePC();
823:                    boolean valPC = fmd.getElement().isDeclaredTypePC();
824:                    if (!keyPC && !valPC)
825:                        return;
826:
827:                    // if we have to copy keys, just clear and re-add; otherwise
828:                    // we can use the entry set to reset the values only
829:                    Map.Entry entry;
830:                    if (!_copy || keyPC) {
831:                        if (_copy)
832:                            map.clear();
833:                        Object key, val;
834:                        for (Iterator itr = orig.entrySet().iterator(); itr
835:                                .hasNext();) {
836:                            entry = (Map.Entry) itr.next();
837:                            key = entry.getKey();
838:                            if (keyPC)
839:                                key = detachInternal(key);
840:                            val = entry.getValue();
841:                            if (valPC)
842:                                val = detachInternal(val);
843:                            if (_copy)
844:                                map.put(key, val);
845:                        }
846:                    } else {
847:                        for (Iterator itr = map.entrySet().iterator(); itr
848:                                .hasNext();) {
849:                            entry = (Map.Entry) itr.next();
850:                            entry.setValue(detachInternal(entry.getValue()));
851:                        }
852:                    }
853:                }
854:            }
855:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.