use of org.datanucleus.state.ObjectProvider in project datanucleus-core by datanucleus.
the class SCOUtils method validateObjectForWriting.
/**
* Method to check if an object to be stored in a SCO container is already persistent, or is managed by a
* different ExecutionContext. If not persistent, this call will persist it.
* If not yet flushed to the datastore this call will flush it.
* @param ec ExecutionContext
* @param object The object
* @param fieldValues Values for any fields when persisting (if the object needs persisting)
* @return Whether the object was persisted during this call
*/
public static boolean validateObjectForWriting(ExecutionContext ec, Object object, FieldValues fieldValues) {
boolean persisted = false;
ApiAdapter api = ec.getApiAdapter();
if (api.isPersistable(object)) {
ExecutionContext objectEC = api.getExecutionContext(object);
if (objectEC != null && ec != objectEC) {
throw new NucleusUserException(Localiser.msg("023009", StringUtils.toJVMIDString(object)), api.getIdForObject(object));
} else if (!api.isPersistent(object)) {
// Not persistent, so either is detached, or needs persisting for first time
boolean exists = false;
if (api.isDetached(object)) {
if (ec.getBooleanProperty(PropertyNames.PROPERTY_ATTACH_SAME_DATASTORE)) {
// Assume that it is detached from this datastore
exists = true;
} else {
// Check if the (attached) object exists in this datastore
try {
Object obj = ec.findObject(api.getIdForObject(object), true, false, object.getClass().getName());
if (obj != null) {
// PM.getObjectById creates a dummy object to represent this object and
// automatically
// enlists it in the txn. Evict it to avoid issues with reachability
ObjectProvider objSM = ec.findObjectProvider(obj);
if (objSM != null) {
ec.evictFromTransaction(objSM);
}
}
exists = true;
} catch (NucleusObjectNotFoundException onfe) {
exists = false;
}
}
}
if (!exists) {
// Persist the object
ec.persistObjectInternal(object, fieldValues, ObjectProvider.PC);
persisted = true;
}
} else {
// Persistent state, but is it flushed to the datastore?
ObjectProvider objectSM = ec.findObjectProvider(object);
if (objectSM.isWaitingToBeFlushedToDatastore()) {
// Process any fieldValues
if (fieldValues != null) {
objectSM.loadFieldValues(fieldValues);
}
// Now flush it
objectSM.flush();
// Mark as being persisted since is now in the datastore
persisted = true;
}
}
}
return persisted;
}
use of org.datanucleus.state.ObjectProvider in project datanucleus-core by datanucleus.
the class FlushOrdered method execute.
/* (non-Javadoc)
* @see org.datanucleus.FlushProcess#execute(org.datanucleus.ExecutionContext, java.util.List, java.util.List, org.datanucleus.flush.OperationQueue)
*/
public List<NucleusOptimisticException> execute(ExecutionContext ec, List<ObjectProvider> primaryOPs, List<ObjectProvider> secondaryOPs, OperationQueue opQueue) {
// Note that opQueue is not processed directly here, but instead will be processed via callbacks from the persistence of other objects
// TODO The opQueue needs to be processed from here instead of via the callbacks, see NUCCORE-904
List<NucleusOptimisticException> optimisticFailures = null;
// Make copy of ObjectProviders so we don't have ConcurrentModification issues
Object[] toFlushPrimary = null;
Object[] toFlushSecondary = null;
try {
if (// Why lock here? should be on overall flush
ec.getMultithreaded()) {
ec.getLock().lock();
}
if (primaryOPs != null) {
toFlushPrimary = primaryOPs.toArray();
primaryOPs.clear();
}
if (secondaryOPs != null) {
toFlushSecondary = secondaryOPs.toArray();
secondaryOPs.clear();
}
} finally {
if (ec.getMultithreaded()) {
ec.getLock().unlock();
}
}
if (NucleusLogger.PERSISTENCE.isDebugEnabled()) {
int total = 0;
if (toFlushPrimary != null) {
total += toFlushPrimary.length;
}
if (toFlushSecondary != null) {
total += toFlushSecondary.length;
}
NucleusLogger.PERSISTENCE.debug(Localiser.msg("010003", total));
}
Set<Class> classesToFlush = null;
if (ec.getNucleusContext().getStoreManager().getQueryManager().getQueryResultsCache() != null) {
classesToFlush = new HashSet();
}
// a). primary dirty objects
if (toFlushPrimary != null) {
for (int i = 0; i < toFlushPrimary.length; i++) {
ObjectProvider op = (ObjectProvider) toFlushPrimary[i];
try {
op.flush();
if (classesToFlush != null && op.getObject() != null) {
classesToFlush.add(op.getObject().getClass());
}
} catch (NucleusOptimisticException oe) {
if (optimisticFailures == null) {
optimisticFailures = new ArrayList();
}
optimisticFailures.add(oe);
}
}
}
// b). secondary dirty objects
if (toFlushSecondary != null) {
for (int i = 0; i < toFlushSecondary.length; i++) {
ObjectProvider op = (ObjectProvider) toFlushSecondary[i];
try {
op.flush();
if (classesToFlush != null && op.getObject() != null) {
classesToFlush.add(op.getObject().getClass());
}
} catch (NucleusOptimisticException oe) {
if (optimisticFailures == null) {
optimisticFailures = new ArrayList();
}
optimisticFailures.add(oe);
}
}
}
if (opQueue != null) {
if (!ec.getStoreManager().usesBackedSCOWrappers()) {
// This ExecutionContext is not using backing store SCO wrappers, so process SCO Operations for cascade delete etc.
opQueue.processOperationsForNoBackingStoreSCOs(ec);
}
opQueue.clearPersistDeleteUpdateOperations();
}
if (classesToFlush != null) {
// Flush any query results from cache for these types
Iterator<Class> queryClsIter = classesToFlush.iterator();
while (queryClsIter.hasNext()) {
Class cls = queryClsIter.next();
ec.getNucleusContext().getStoreManager().getQueryManager().evictQueryResultsForType(cls);
}
}
return optimisticFailures;
}
use of org.datanucleus.state.ObjectProvider in project datanucleus-core by datanucleus.
the class FlushNonReferential method flushDeleteInsertUpdateGrouped.
/**
* Method that does the flushing of the passed ObjectProviders, grouping them into all DELETEs, then all INSERTs,
* finally all UPDATEs. The StorePersistenceHandler will get calls to <i>deleteObjects</i>, <i>insertObjects</i>
* and <i>updateObject</i> (for each other one). Note that this is in a separate method to allow calls by
* other FlushProcesses that want to take advantage of the basic flush method without
* @param opsToFlush The ObjectProviders to process
* @param ec ExecutionContext
* @return Any optimistic verification exceptions thrown during flush
*/
public List<NucleusOptimisticException> flushDeleteInsertUpdateGrouped(Set<ObjectProvider> opsToFlush, ExecutionContext ec) {
List<NucleusOptimisticException> optimisticFailures = null;
Set<Class> classesToFlush = null;
if (ec.getNucleusContext().getStoreManager().getQueryManager().getQueryResultsCache() != null) {
classesToFlush = new HashSet();
}
Set<ObjectProvider> opsToDelete = new HashSet<ObjectProvider>();
Set<ObjectProvider> opsToInsert = new HashSet<ObjectProvider>();
Iterator<ObjectProvider> opIter = opsToFlush.iterator();
while (opIter.hasNext()) {
ObjectProvider op = opIter.next();
if (op.isEmbedded()) {
// Embedded have nothing to flush since the owner manages it
op.markAsFlushed();
opIter.remove();
} else {
if (classesToFlush != null && op.getObject() != null) {
classesToFlush.add(op.getObject().getClass());
}
if (op.getLifecycleState().isNew() && !op.isFlushedToDatastore() && !op.isFlushedNew()) {
// P_NEW and not yet flushed to datastore
opsToInsert.add(op);
opIter.remove();
} else if (op.getLifecycleState().isDeleted() && !op.isFlushedToDatastore()) {
if (!op.getLifecycleState().isNew()) {
// P_DELETED
opsToDelete.add(op);
opIter.remove();
} else if (op.getLifecycleState().isNew() && op.isFlushedNew()) {
// P_NEW_DELETED already persisted
opsToDelete.add(op);
opIter.remove();
}
}
}
}
if (NucleusLogger.PERSISTENCE.isDebugEnabled()) {
NucleusLogger.PERSISTENCE.debug(Localiser.msg("010046", opsToDelete.size(), opsToInsert.size(), opsToFlush.size()));
}
StorePersistenceHandler persistenceHandler = ec.getStoreManager().getPersistenceHandler();
if (!opsToDelete.isEmpty()) {
// TODO This omits some parts of sm.internalDeletePersistent
for (ObjectProvider op : opsToDelete) {
op.setFlushing(true);
ec.getCallbackHandler().preDelete(op.getObject());
}
try {
persistenceHandler.deleteObjects(opsToDelete.toArray(new ObjectProvider[opsToDelete.size()]));
} catch (NucleusOptimisticException noe) {
optimisticFailures = new ArrayList();
Throwable[] nestedExcs = noe.getNestedExceptions();
if (nestedExcs != null && nestedExcs.length > 1) {
NucleusOptimisticException[] noes = (NucleusOptimisticException[]) nestedExcs;
for (int i = 0; i < nestedExcs.length; i++) {
optimisticFailures.add(noes[i]);
}
} else {
optimisticFailures.add(noe);
}
}
for (ObjectProvider op : opsToDelete) {
ec.getCallbackHandler().postDelete(op.getObject());
op.setFlushedNew(false);
op.markAsFlushed();
op.setFlushing(false);
}
}
if (!opsToInsert.isEmpty()) {
// TODO This omits some parts of sm.internalMakePersistent
for (ObjectProvider op : opsToInsert) {
op.setFlushing(true);
ec.getCallbackHandler().preStore(op.getObject());
// TODO Make sure identity is set since user could have updated fields in preStore
}
persistenceHandler.insertObjects(opsToInsert.toArray(new ObjectProvider[opsToInsert.size()]));
for (ObjectProvider op : opsToInsert) {
ec.getCallbackHandler().postStore(op.getObject());
op.setFlushedNew(true);
op.markAsFlushed();
op.setFlushing(false);
// Update the object in the cache(s) now that version/id are set
ec.putObjectIntoLevel1Cache(op);
}
}
if (!opsToFlush.isEmpty()) {
// Objects to update
for (ObjectProvider op : opsToFlush) {
try {
op.flush();
} catch (NucleusOptimisticException oe) {
if (optimisticFailures == null) {
optimisticFailures = new ArrayList();
}
optimisticFailures.add(oe);
}
}
}
if (classesToFlush != null) {
// Flush any query results from cache for these types
Iterator<Class> queryClsIter = classesToFlush.iterator();
while (queryClsIter.hasNext()) {
Class cls = queryClsIter.next();
ec.getNucleusContext().getStoreManager().getQueryManager().evictQueryResultsForType(cls);
}
}
return optimisticFailures;
}
use of org.datanucleus.state.ObjectProvider in project datanucleus-core by datanucleus.
the class DeleteFieldManager method processPersistable.
/**
* Utility method to process the passed persistable object.
* @param pc The PC object
*/
protected void processPersistable(Object pc) {
ObjectProvider pcOP = op.getExecutionContext().findObjectProvider(pc);
if (pcOP != null) {
if (pcOP.isDeleting() || pcOP.becomingDeleted()) {
// Already becoming deleted so jump out
return;
}
}
// Delete it
op.getExecutionContext().deleteObjectInternal(pc);
}
use of org.datanucleus.state.ObjectProvider in project datanucleus-core by datanucleus.
the class PersistFieldManager method processMapContainer.
private void processMapContainer(int fieldNumber, Object container, AbstractMemberMetaData mmd) {
TypeManager typeManager = op.getExecutionContext().getTypeManager();
ContainerHandler<Object, MapContainerAdapter<Object>> containerHandler = typeManager.getContainerHandler(mmd.getType());
ApiAdapter api = op.getExecutionContext().getApiAdapter();
// Process all keys, values of the Map that are PC
MapContainerAdapter<Object> mapAdapter = containerHandler.getAdapter(container);
for (Entry<Object, Object> entry : mapAdapter.entries()) {
Object mapKey = entry.getKey();
Object mapValue = entry.getValue();
Object newMapKey = mapKey;
Object newMapValue = mapValue;
if (api.isPersistable(mapKey)) {
// Persist (or attach) the key
int mapKeyObjectType = mmd.getMap().isEmbeddedKey() || mmd.getMap().isSerializedKey() ? ObjectProvider.EMBEDDED_MAP_KEY_PC : ObjectProvider.PC;
newMapKey = processPersistable(mapKey, fieldNumber, mapKeyObjectType);
}
if (api.isPersistable(mapValue)) {
// Persist (or attach) the value
int mapValueObjectType = mmd.getMap().isEmbeddedValue() || mmd.getMap().isSerializedValue() ? ObjectProvider.EMBEDDED_MAP_VALUE_PC : ObjectProvider.PC;
newMapValue = processPersistable(mapValue, fieldNumber, mapValueObjectType);
}
if (newMapKey != mapKey || newMapValue != mapValue) {
// Maybe we have just have attached key or value
boolean updateKey = false;
boolean updateValue = false;
if (newMapKey != mapKey) {
ObjectProvider keyOP = op.getExecutionContext().findObjectProvider(newMapKey);
if (keyOP.getReferencedPC() != null) {
// Attaching the key
updateKey = true;
}
}
if (newMapValue != mapValue) {
ObjectProvider valOP = op.getExecutionContext().findObjectProvider(newMapValue);
if (valOP.getReferencedPC() != null) {
// Attaching the value
updateValue = true;
}
}
if (updateKey) {
mapAdapter.remove(mapKey);
mapAdapter.put(newMapKey, updateValue ? newMapValue : mapValue);
} else if (updateValue) {
mapAdapter.put(mapKey, newMapValue);
}
}
}
}
Aggregations