| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| package org.apache.openjpa.kernel; |
| |
| import java.util.BitSet; |
| import java.util.Collection; |
| |
| import org.apache.openjpa.conf.OpenJPAConfiguration; |
| import org.apache.openjpa.enhance.PersistenceCapable; |
| import org.apache.openjpa.meta.ClassMetaData; |
| import org.apache.openjpa.meta.FieldMetaData; |
| import org.apache.openjpa.util.Proxy; |
| |
| /** |
| * Handles detaching instances. |
| */ |
| public class DetachManagerLite { |
| private final boolean _detachProxies; |
| private final TransferFieldManager _tsm; |
| |
| public DetachManagerLite(OpenJPAConfiguration conf) { |
| _detachProxies = conf.getDetachStateInstance().getDetachProxyFields(); |
| _tsm = new TransferFieldManager(); |
| } |
| |
| /** |
| * This method will detach all provided StateManagers in place. |
| * |
| * @param states |
| * The StateManagers to be detached. |
| */ |
| public void detachAll(Collection<StateManagerImpl> states) { |
| |
| for (StateManagerImpl sm : states) { |
| ClassMetaData cmd = sm.getMetaData(); |
| if (sm.isPersistent() && cmd.isDetachable()) { |
| PersistenceCapable pc = sm.getPersistenceCapable(); |
| if (!pc.pcIsDetached()) { |
| // Detach proxy fields. |
| BitSet loaded = sm.getLoaded(); |
| for (FieldMetaData fmd : cmd.getProxyFields()) { |
| if (loaded.get(fmd.getIndex())) { |
| detachProxyField(fmd, pc, sm, _tsm); |
| } |
| } |
| pc.pcReplaceStateManager(null); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Detach the provided proxy field. |
| * |
| * @param fmd |
| * The field to be detached. |
| * @param pc |
| * The PersistenceCapable that the field belongs to. |
| * @param sm |
| * The StateManagerImpl that the PersistenceCapable belongs to. |
| */ |
| private void detachProxyField(FieldMetaData fmd, PersistenceCapable pc, |
| StateManagerImpl sm, TransferFieldManager fm) { |
| |
| int fieldIndex = fmd.getIndex(); |
| if (fmd.isLRS()) { |
| // need to null out LRS fields. |
| nullField(fieldIndex, pc, sm, fm); |
| } else { |
| Object o = sm.fetchObject(fieldIndex); |
| if (o instanceof Proxy) { |
| // Get unproxied object and replace |
| Proxy proxy = (Proxy) o; |
| if (!_detachProxies) { |
| // Even if we're not detaching proxies, we need to remove the reference to the SM. |
| proxy.setOwner(null, -1); |
| return; |
| } |
| Object unproxied = proxy.copy(proxy); |
| fm.storeObjectField(fieldIndex, unproxied); |
| sm.replaceField(pc, fm, fieldIndex); |
| fm.clear(); |
| // clean up old proxy |
| proxy.setOwner(null, -1); |
| if (proxy.getChangeTracker() != null) { |
| proxy.getChangeTracker().stopTracking(); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Private worker method that replaces the value at fieldIndex in sm with null. |
| * |
| * @param fieldIndex |
| * The index of the field to be nulled out. |
| * @param pc |
| * The PersistenceCapable that the field belongs to. |
| * @param sm |
| * The StateManagerImpl that the PersistenceCapable belongs to. |
| */ |
| private void nullField(int fieldIndex, PersistenceCapable pc, StateManagerImpl sm, TransferFieldManager fm) { |
| fm.storeObjectField(fieldIndex, null); |
| sm.replaceField(pc, fm, fieldIndex); |
| fm.clear(); |
| } |
| } |