use of org.apache.cayenne.reflect.ClassDescriptor in project cayenne by apache.
the class DataContext method registerNewObject.
/**
* Registers a transient object with the context, recursively registering
* all transient persistent objects attached to this object via
* relationships.
* <p>
* <i>Note that since 3.0 this method takes Object as an argument instead of
* a {@link DataObject}.</i>
*
* @param object
* new object that needs to be made persistent.
*/
@Override
public void registerNewObject(Object object) {
if (object == null) {
throw new NullPointerException("Can't register null object.");
}
ObjEntity entity = getEntityResolver().getObjEntity((Persistent) object);
if (entity == null) {
throw new IllegalArgumentException("Can't find ObjEntity for Persistent class: " + object.getClass().getName() + ", class is likely not mapped.");
}
final Persistent persistent = (Persistent) object;
// sanity check - maybe already registered
if (persistent.getObjectId() != null) {
if (persistent.getObjectContext() == this) {
// already registered, just ignore
return;
} else if (persistent.getObjectContext() != null) {
throw new IllegalStateException("Persistent is already registered with another DataContext. " + "Try using 'localObjects()' instead.");
}
} else {
persistent.setObjectId(ObjectId.of(entity.getName()));
}
ClassDescriptor descriptor = getEntityResolver().getClassDescriptor(entity.getName());
if (descriptor == null) {
throw new IllegalArgumentException("Invalid entity name: " + entity.getName());
}
injectInitialValue(object);
// now we need to find all arc changes, inject missing value holders and
// pull in
// all transient connected objects
descriptor.visitProperties(new PropertyVisitor() {
public boolean visitToMany(ToManyProperty property) {
property.injectValueHolder(persistent);
if (!property.isFault(persistent)) {
Object value = property.readProperty(persistent);
@SuppressWarnings("unchecked") Collection<Map.Entry> collection = (value instanceof Map) ? ((Map) value).entrySet() : (Collection) value;
for (Object target : collection) {
if (target instanceof Persistent) {
Persistent targetDO = (Persistent) target;
// make sure it is registered
registerNewObject(targetDO);
getObjectStore().arcCreated(persistent.getObjectId(), targetDO.getObjectId(), new ArcId(property));
}
}
}
return true;
}
public boolean visitToOne(ToOneProperty property) {
Object target = property.readPropertyDirectly(persistent);
if (target instanceof Persistent) {
Persistent targetDO = (Persistent) target;
// make sure it is registered
registerNewObject(targetDO);
getObjectStore().arcCreated(persistent.getObjectId(), targetDO.getObjectId(), new ArcId(property));
}
return true;
}
public boolean visitAttribute(AttributeProperty property) {
return true;
}
});
}
use of org.apache.cayenne.reflect.ClassDescriptor in project cayenne by apache.
the class BaseContext method prepareForAccess.
@Override
public void prepareForAccess(Persistent object, String property, boolean lazyFaulting) {
if (object.getPersistenceState() == PersistenceState.HOLLOW) {
ObjectId oid = object.getObjectId();
List<?> objects = performQuery(new ObjectIdQuery(oid, false, ObjectIdQuery.CACHE));
if (objects.size() == 0) {
throw new FaultFailureException("Error resolving fault, no matching row exists in the database for ObjectId: " + oid);
} else if (objects.size() > 1) {
throw new FaultFailureException("Error resolving fault, more than one row exists in the database for ObjectId: " + oid);
}
// 5/28/2013 - Commented out this block to allow for modifying
// objects in the postLoad callback
// sanity check...
// if (object.getPersistenceState() != PersistenceState.COMMITTED) {
//
// String state =
// PersistenceState.persistenceStateName(object.getPersistenceState());
//
// // TODO: andrus 4/13/2006, modified and deleted states are
// // possible due to
// // a race condition, should we handle them here?
// throw new
// FaultFailureException("Error resolving fault for ObjectId: " +
// oid + " and state (" + state
// +
// "). Possible cause - matching row is missing from the database.");
// }
}
// resolve relationship fault
if (lazyFaulting && property != null) {
ClassDescriptor classDescriptor = getEntityResolver().getClassDescriptor(object.getObjectId().getEntityName());
PropertyDescriptor propertyDescriptor = classDescriptor.getProperty(property);
// be used.
if (propertyDescriptor == null) {
final StringBuilder errorMessage = new StringBuilder();
errorMessage.append(String.format("Property '%s' is not declared for entity '%s'.", property, object.getObjectId().getEntityName()));
errorMessage.append(" Declared properties are: ");
// Grab each of the declared properties.
final List<String> properties = new ArrayList<>();
classDescriptor.visitProperties(new PropertyVisitor() {
@Override
public boolean visitAttribute(final AttributeProperty property) {
properties.add(property.getName());
return true;
}
@Override
public boolean visitToOne(final ToOneProperty property) {
properties.add(property.getName());
return true;
}
@Override
public boolean visitToMany(final ToManyProperty property) {
properties.add(property.getName());
return true;
}
});
// Now add the declared property names to the error message.
boolean first = true;
for (String declaredProperty : properties) {
if (first) {
errorMessage.append(String.format("'%s'", declaredProperty));
first = false;
} else {
errorMessage.append(String.format(", '%s'", declaredProperty));
}
}
errorMessage.append(".");
throw new CayenneRuntimeException(errorMessage.toString());
}
// this should trigger fault resolving
propertyDescriptor.readProperty(object);
}
}
use of org.apache.cayenne.reflect.ClassDescriptor in project cayenne by apache.
the class BaseContext method localObject.
/**
* @since 3.1
*/
@Override
public <T extends Persistent> T localObject(T objectFromAnotherContext) {
if (objectFromAnotherContext == null) {
throw new NullPointerException("Null object argument");
}
ObjectId id = objectFromAnotherContext.getObjectId();
// first look for the ID in the local GraphManager
synchronized (getGraphManager()) {
@SuppressWarnings("unchecked") T localObject = (T) getGraphManager().getNode(id);
if (localObject != null) {
return localObject;
}
// create a hollow object, optimistically assuming that the ID we got from
// 'objectFromAnotherContext' is a valid ID either in the parent context or in the DB.
// This essentially defers possible FaultFailureExceptions.
ClassDescriptor descriptor = getEntityResolver().getClassDescriptor(id.getEntityName());
@SuppressWarnings("unchecked") T persistent = (T) descriptor.createObject();
persistent.setObjectContext(this);
persistent.setObjectId(id);
persistent.setPersistenceState(PersistenceState.HOLLOW);
getGraphManager().registerNode(id, persistent);
return persistent;
}
}
use of org.apache.cayenne.reflect.ClassDescriptor in project cayenne by apache.
the class PrefetchNodeStage method processJoint.
private void processJoint(TranslatorContext context) {
QueryMetadata queryMetadata = context.getMetadata();
PrefetchTreeNode prefetch = queryMetadata.getPrefetchTree();
if (prefetch == null) {
return;
}
ObjEntity objEntity = queryMetadata.getObjEntity();
boolean warnPrefetchWithLimit = false;
for (PrefetchTreeNode node : prefetch.adjacentJointNodes()) {
Expression prefetchExp = ExpressionFactory.exp(node.getPath());
ASTDbPath dbPrefetch = (ASTDbPath) objEntity.translateToDbPath(prefetchExp);
final String dbPath = dbPrefetch.getPath();
DbEntity dbEntity = objEntity.getDbEntity();
PathComponents components = new PathComponents(dbPath);
StringBuilder fullPath = new StringBuilder();
for (String c : components.getAll()) {
DbRelationship rel = dbEntity.getRelationship(c);
if (rel == null) {
throw new CayenneRuntimeException("Unable to resolve path %s for entity %s", dbPath, objEntity.getName());
}
if (fullPath.length() > 0) {
fullPath.append('.');
}
context.getTableTree().addJoinTable("p:" + fullPath.append(c).toString(), rel, JoinType.LEFT_OUTER);
dbEntity = rel.getTargetEntity();
}
ObjRelationship targetRel = (ObjRelationship) prefetchExp.evaluate(objEntity);
ClassDescriptor prefetchClassDescriptor = context.getResolver().getClassDescriptor(targetRel.getTargetEntityName());
DescriptorColumnExtractor columnExtractor = new DescriptorColumnExtractor(context, prefetchClassDescriptor);
columnExtractor.extract("p:" + dbPath);
if (!warnPrefetchWithLimit && targetRel.isToMany() && (queryMetadata.getFetchLimit() > 0 || queryMetadata.getFetchOffset() > 0)) {
warnPrefetchWithLimit = true;
}
}
// warn about a potentially faulty joint prefetch + limit combination
if (warnPrefetchWithLimit) {
LOGGER.warn("The query uses both limit/offset and a joint prefetch, this most probably will lead to an incorrect result. " + "Either use disjointById prefetch or get a full result set.");
}
}
use of org.apache.cayenne.reflect.ClassDescriptor in project cayenne by apache.
the class QualifierTranslationStage method perform.
@Override
public void perform(TranslatorContext context) {
QualifierTranslator translator = context.getQualifierTranslator();
Expression expression = context.getQuery().getQualifier();
// Attaching Obj entity's qualifier
ObjEntity entity = context.getMetadata().getObjEntity();
if (entity != null) {
ClassDescriptor descriptor = context.getMetadata().getClassDescriptor();
Expression entityQualifier = descriptor.getEntityInheritanceTree().qualifierForEntityAndSubclasses();
if (entityQualifier != null) {
expression = expression == null ? entityQualifier : expression.andExp(entityQualifier);
}
}
Node qualifierNode = translator.translate(expression);
context.setQualifierNode(qualifierNode);
}
Aggregations