Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* 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.lang.reflect.Array;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Set;
import org.apache.openjpa.enhance.PersistenceCapable;
import org.apache.openjpa.enhance.StateManager;
import org.apache.openjpa.lib.util.Localizer;
import org.apache.openjpa.meta.ClassMetaData;
import org.apache.openjpa.meta.FieldMetaData;
import org.apache.openjpa.meta.JavaTypes;
import org.apache.openjpa.meta.ValueMetaData;
import org.apache.openjpa.util.InternalException;
import org.apache.openjpa.util.UserException;
/**
* Strategy for attaching objects.
*
* @author Marc Prud'hommeaux
* @author Steve Kim
*/
abstract class AttachStrategy
extends TransferFieldManager {
private static final Localizer _loc = Localizer.forPackage
(AttachStrategy.class);
/**
* Attach.
*
* @param manager manager holding cache of attached instances
* @param toAttach detached instance
* @param meta metadata for the instance being attached
* @param into instance we're attaching into
* @param owner state manager for into
* @param ownerMeta field we traversed to find toAttach
* @param explicit whether to make new instances explicitly persistent
*/
public abstract Object attach(AttachManager manager,
Object toAttach, ClassMetaData meta, PersistenceCapable into,
OpenJPAStateManager owner, ValueMetaData ownerMeta, boolean explicit);
/**
* Return the identity of the given detached instance.
*/
protected abstract Object getDetachedObjectId(AttachManager manager,
Object toAttach);
/**
* Provide the given field into this field manager.
*/
protected abstract void provideField(Object toAttach, StateManagerImpl sm,
int field);
/**
* Return a PNew/PNewProvisional managed object for the given detached
* instance.
*/
protected StateManagerImpl persist(AttachManager manager,
PersistenceCapable pc, ClassMetaData meta, Object appId,
boolean explicit) {
PersistenceCapable newInstance;
if (!manager.getCopyNew())
newInstance = pc;
else if (appId == null)
// datastore identity or application identity with generated keys
newInstance = pc.pcNewInstance(null, false);
else // application identity: use existing fields
newInstance = pc.pcNewInstance(null, appId, false);
StateManagerImpl sm = (StateManagerImpl) manager.getBroker().persist
(newInstance, appId, explicit, manager.getBehavior(), !manager.getCopyNew());
attachPCKeyFields(pc, sm, meta, manager);
return sm;
}
private void attachPCKeyFields(PersistenceCapable fromPC,
StateManagerImpl sm, ClassMetaData meta, AttachManager manager) {
if (fromPC.pcGetStateManager() == null) {
fromPC.pcReplaceStateManager(sm);
FieldMetaData[] fmds = meta.getDefinedFields();
for (FieldMetaData fmd : fmds) {
if (fmd.isPrimaryKey() && fmd.getDeclaredTypeCode() == JavaTypes.PC) {
attachField(manager, fromPC, sm, fmd, true);
}
}
fromPC.pcReplaceStateManager(null);
}
}
/**
* Attach the given field into the given instance.
*
* @param toAttach the detached persistent instance
* @param sm state manager for the managed instance we're copying
* into; toAttach also uses this state manager
* @param fmd metadata on the field we're copying
* @param nullLoaded if false, nulls will be considered unloaded and will
* not be attached
*/
protected boolean attachField(AttachManager manager, Object toAttach,
StateManagerImpl sm, FieldMetaData fmd, boolean nullLoaded) {
if (fmd.isVersion()
|| fmd.getManagement() != FieldMetaData.MANAGE_PERSISTENT)
return false;
PersistenceCapable into = sm.getPersistenceCapable();
int i = fmd.getIndex();
provideField(toAttach, sm, i);
int set = StateManager.SET_ATTACH;
Object val;
switch (fmd.getDeclaredTypeCode()) {
case JavaTypes.BOOLEAN:
sm.settingBooleanField(into, i, sm.fetchBooleanField(i),
fetchBooleanField(i), set);
break;
case JavaTypes.BYTE:
sm.settingByteField(into, i, sm.fetchByteField(i),
fetchByteField(i), set);
break;
case JavaTypes.CHAR:
sm.settingCharField(into, i, sm.fetchCharField(i),
fetchCharField(i), set);
break;
case JavaTypes.DOUBLE:
sm.settingDoubleField(into, i, sm.fetchDoubleField(i),
fetchDoubleField(i), set);
break;
case JavaTypes.FLOAT:
sm.settingFloatField(into, i, sm.fetchFloatField(i),
fetchFloatField(i), set);
break;
case JavaTypes.INT:
sm.settingIntField(into, i, sm.fetchIntField(i),
fetchIntField(i), set);
break;
case JavaTypes.LONG:
sm.settingLongField(into, i, sm.fetchLongField(i),
fetchLongField(i), set);
break;
case JavaTypes.SHORT:
sm.settingShortField(into, i, sm.fetchShortField(i),
fetchShortField(i), set);
break;
case JavaTypes.STRING:
String sval = fetchStringField(i);
if (sval == null && !nullLoaded)
return false;
sm.settingStringField(into, i, sm.fetchStringField(i), sval,
set);
break;
case JavaTypes.DATE:
case JavaTypes.CALENDAR:
case JavaTypes.LOCAL_DATE:
case JavaTypes.LOCAL_TIME:
case JavaTypes.LOCAL_DATETIME:
case JavaTypes.OFFSET_TIME:
case JavaTypes.OFFSET_DATETIME:
case JavaTypes.NUMBER:
case JavaTypes.BOOLEAN_OBJ:
case JavaTypes.BYTE_OBJ:
case JavaTypes.CHAR_OBJ:
case JavaTypes.DOUBLE_OBJ:
case JavaTypes.FLOAT_OBJ:
case JavaTypes.INT_OBJ:
case JavaTypes.LONG_OBJ:
case JavaTypes.SHORT_OBJ:
case JavaTypes.BIGDECIMAL:
case JavaTypes.BIGINTEGER:
case JavaTypes.LOCALE:
case JavaTypes.OBJECT:
case JavaTypes.OID:
case JavaTypes.ENUM:
val = fetchObjectField(i);
if (val == null && !nullLoaded)
return false;
sm.settingObjectField(into, i, sm.fetchObjectField(i), val,
set);
break;
case JavaTypes.PC:
case JavaTypes.PC_UNTYPED:
Object frmpc = fetchObjectField(i);
if (frmpc == null && !nullLoaded)
return false;
OpenJPAStateManager tosm = manager.getBroker().getStateManager
(sm.fetchObjectField(i));
PersistenceCapable topc = (tosm == null) ? null
: tosm.getPersistenceCapable();
if (frmpc != null || topc != null) {
if (fmd.getCascadeAttach() == ValueMetaData.CASCADE_NONE) {
// Use the attached copy of the object, if available
PersistenceCapable cpy = manager.getAttachedCopy(frmpc);
if (cpy != null) {
frmpc = cpy;
} else {
frmpc = getReference(manager, frmpc, sm, fmd);
}
}
else {
PersistenceCapable intopc = topc;
if (!fmd.isEmbeddedPC() && frmpc != null && topc != null
&& !Objects.equals(topc.pcFetchObjectId(),
manager.getDetachedObjectId(frmpc))) {
intopc = null;
}
frmpc = manager.attach(frmpc, intopc, sm, fmd, false);
}
if (frmpc != topc)
sm.settingObjectField(into, i, topc, frmpc, set);
}
break;
case JavaTypes.COLLECTION:
Collection frmc = (Collection) fetchObjectField(i);
if (frmc == null && !nullLoaded)
return false;
Collection toc = (Collection) sm.fetchObjectField(i);
if ((toc != null && !toc.isEmpty())
|| frmc != null && !frmc.isEmpty()) {
if (frmc == null)
sm.settingObjectField(into, i, toc, null, set);
else if (toc == null) {
sm.settingObjectField(into, i, null,
attachCollection(manager, frmc, sm, fmd), set);
} else if (toc instanceof Set && frmc instanceof Set)
replaceCollection(manager, frmc, toc, sm, fmd);
else {
sm.settingObjectField(into, i, toc,
replaceList(manager, frmc, toc, sm, fmd), set);
}
}
break;
case JavaTypes.MAP:
Map frmm = (Map) fetchObjectField(i);
if (frmm == null && !nullLoaded)
return false;
Map tom = (Map) sm.fetchObjectField(i);
if ((tom != null && !tom.isEmpty())
|| (frmm != null && !frmm.isEmpty())) {
if (frmm == null)
sm.settingObjectField(into, i, tom, null, set);
else if (tom == null)
sm.settingObjectField(into, i, null,
attachMap(manager, frmm, sm, fmd), set);
else
replaceMap(manager, frmm, tom, sm, fmd);
}
break;
case JavaTypes.ARRAY:
Object frma = fetchObjectField(i);
if (frma == null && !nullLoaded)
return false;
Object toa = sm.fetchObjectField(i);
if ((toa != null && Array.getLength(toa) > 0)
|| (frma != null && Array.getLength(frma) > 0)) {
if (frma == null)
sm.settingObjectField(into, i, toa, null, set);
else
sm.settingObjectField(into, i, toa,
replaceArray(manager, frma, toa, sm, fmd), set);
}
break;
default:
throw new InternalException(fmd.toString());
}
return true;
}
/**
* Return a managed, possibly hollow reference for the given detached
* object.
*/
protected Object getReference(AttachManager manager, Object toAttach, OpenJPAStateManager sm, ValueMetaData vmd) {
if (toAttach == null)
return null;
if (manager.getBroker().isNew(toAttach)) {
// Check if toAttach is already mapped to a managed instance
PersistenceCapable pc = manager.getAttachedCopy(toAttach);
if (pc != null) {
return pc;
} else {
return toAttach;
}
} else if (manager.getBroker().isPersistent(toAttach)) {
return toAttach;
} else if (manager.getBroker().isDetached(toAttach)) {
Object oid = manager.getDetachedObjectId(toAttach);
if (oid != null) {
return manager.getBroker().find(oid, false, null);
}
}
throw new UserException(_loc.get("cant-cascade-attach", vmd)).setFailedObject(toAttach);
}
/**
* Replace the contents of toc with the contents of
* frmc. Neither collection is null.
*/
private void replaceCollection(AttachManager manager, Collection frmc,
Collection toc, OpenJPAStateManager sm, FieldMetaData fmd) {
// if frmc collection is empty, just clear toc
if (frmc.isEmpty()) {
if (!toc.isEmpty())
toc.clear();
return;
}
// if this is a pc collection, attach all instances
boolean pc = fmd.getElement().isDeclaredTypePC();
if (pc)
frmc = attachCollection(manager, frmc, sm, fmd);
// remove all elements from the toc collection that aren't in frmc
toc.retainAll(frmc);
// now add all elements that are in frmc but not toc
if (frmc.size() != toc.size()) {
for (Object ob : frmc) {
if (!toc.contains(ob))
toc.add(ob);
}
}
}
/**
* Return a new collection with the attached contents of the given one.
*/
protected Collection attachCollection(AttachManager manager,
Collection orig, OpenJPAStateManager sm, FieldMetaData fmd) {
Collection coll = copyCollection(manager, orig, fmd, sm);
ValueMetaData vmd = fmd.getElement();
if (!vmd.isDeclaredTypePC())
return coll;
// unfortunately we have to clear the original and re-add
coll.clear();
Object elem;
for (Iterator itr = orig.iterator(); itr.hasNext();) {
if (vmd.getCascadeAttach() == ValueMetaData.CASCADE_NONE)
elem = getReference(manager, itr.next(), sm, vmd);
else
elem = manager.attach(itr.next(), null, sm, vmd, false);
coll.add(elem);
}
return coll;
}
/**
* Copies the given collection.
*/
private Collection copyCollection(AttachManager manager, Collection orig,
FieldMetaData fmd) {
Collection coll = manager.getProxyManager().copyCollection(orig);
if (coll == null)
throw new UserException(_loc.get("not-copyable", fmd));
return coll;
}
/**
* Copies the given collection.
*/
private Collection copyCollection(AttachManager manager, Collection orig,
FieldMetaData fmd, OpenJPAStateManager sm) {
if (orig == null)
throw new UserException(_loc.get("not-copyable", fmd));
try {
return copyCollection(manager, orig, fmd);
} catch (Exception e) {
Collection coll = (Collection) sm.newFieldProxy(fmd.getIndex());
coll.addAll(orig);
return coll;
}
}
/**
* Copies the given map.
*/
private Map copyMap(AttachManager manager, Map orig,
FieldMetaData fmd, OpenJPAStateManager sm) {
if (orig == null)
throw new UserException(_loc.get("not-copyable", fmd));
try {
return manager.getProxyManager().copyMap(orig);
} catch (Exception e) {
Map