use of org.apache.cayenne.query.PrefetchTreeNode in project cayenne by apache.
the class ObjectDetachOperation method detach.
/**
* "Detaches" an object from its context by creating an unattached copy. The copy is
* created using target descriptor of this operation that may be different from the
* object descriptor passed to this method.
*/
public Object detach(Object object, ClassDescriptor descriptor, final PrefetchTreeNode prefetchTree) {
if (!(object instanceof Persistent)) {
throw new CayenneRuntimeException("Expected Persistent, got: %s", object);
}
final Persistent source = (Persistent) object;
ObjectId id = source.getObjectId();
// sanity check
if (id == null) {
throw new CayenneRuntimeException("Server returned an object without an id: %s", source);
}
Object seenTarget = seen.get(id);
if (seenTarget != null) {
return seenTarget;
}
descriptor = descriptor.getSubclassDescriptor(source.getClass());
// presumably id's entity name should be of the right subclass.
final ClassDescriptor targetDescriptor = targetResolver.getClassDescriptor(id.getEntityName());
final Persistent target = (Persistent) targetDescriptor.createObject();
target.setObjectId(id);
seen.put(id, target);
descriptor.visitProperties(new PropertyVisitor() {
private void fillReverseRelationship(Object destinationTarget, ArcProperty property) {
ArcProperty clientProperty = (ArcProperty) targetDescriptor.getProperty(property.getName());
if (clientProperty != null) {
ArcProperty clientReverse = clientProperty.getComplimentaryReverseArc();
if (clientReverse instanceof ToOneProperty) {
clientReverse.writeProperty(destinationTarget, null, target);
}
}
}
public boolean visitToOne(ToOneProperty property) {
if (prefetchTree != null) {
PrefetchTreeNode child = prefetchTree.getNode(property.getName());
if (child != null) {
Object destinationSource = property.readProperty(source);
Object destinationTarget = destinationSource != null ? detach(destinationSource, property.getTargetDescriptor(), child) : null;
if (destinationTarget != null) {
fillReverseRelationship(destinationTarget, property);
}
ToOneProperty targetProperty = (ToOneProperty) targetDescriptor.getProperty(property.getName());
Object oldTarget = targetProperty.isFault(target) ? null : targetProperty.readProperty(target);
targetProperty.writeProperty(target, oldTarget, destinationTarget);
}
}
return true;
}
public boolean visitToMany(ToManyProperty property) {
if (prefetchTree != null) {
PrefetchTreeNode child = prefetchTree.getNode(property.getName());
if (child != null) {
Object value = property.readProperty(source);
Object targetValue;
if (property instanceof ToManyMapProperty) {
Map<?, ?> map = (Map) value;
Map targetMap = new HashMap();
for (Entry entry : map.entrySet()) {
Object destinationSource = entry.getValue();
Object destinationTarget = destinationSource != null ? detach(destinationSource, property.getTargetDescriptor(), child) : null;
if (destinationTarget != null) {
fillReverseRelationship(destinationTarget, property);
}
targetMap.put(entry.getKey(), destinationTarget);
}
targetValue = targetMap;
} else {
Collection collection = (Collection) value;
Collection targetCollection = new ArrayList(collection.size());
for (Object destinationSource : collection) {
Object destinationTarget = destinationSource != null ? detach(destinationSource, property.getTargetDescriptor(), child) : null;
if (destinationTarget != null) {
fillReverseRelationship(destinationTarget, property);
}
targetCollection.add(destinationTarget);
}
targetValue = targetCollection;
}
ToManyProperty targetProperty = (ToManyProperty) targetDescriptor.getProperty(property.getName());
targetProperty.writeProperty(target, null, targetValue);
}
}
return true;
}
public boolean visitAttribute(AttributeProperty property) {
PropertyDescriptor targetProperty = targetDescriptor.getProperty(property.getName());
if (!property.getAttribute().isLazy()) {
targetProperty.writeProperty(target, null, property.readProperty(source));
} else {
targetProperty.writeProperty(target, null, new AttributeFault(property));
}
return true;
}
});
return target;
}
use of org.apache.cayenne.query.PrefetchTreeNode in project cayenne by apache.
the class PrefetchProcessorJointNode method buildRowMapping.
/**
* Configures row columns mapping for this node entity.
*/
private void buildRowMapping() {
final Map<String, ColumnDescriptor> targetSource = new TreeMap<>();
// build a DB path .. find parent node that terminates the joint group...
PrefetchTreeNode jointRoot = this;
while (jointRoot.getParent() != null && !jointRoot.isDisjointPrefetch() && !jointRoot.isDisjointByIdPrefetch()) {
jointRoot = jointRoot.getParent();
}
final String prefix;
if (jointRoot != this) {
Expression objectPath = ExpressionFactory.exp(getPath(jointRoot));
ASTPath translated = (ASTPath) ((PrefetchProcessorNode) jointRoot).getResolver().getEntity().translateToDbPath(objectPath);
// make sure we do not include "db:" prefix
prefix = translated.getOperand(0) + ".";
} else {
prefix = "";
}
if (getParent() != null && !getParent().isPhantom() && getIncoming() != null && !getIncoming().getRelationship().isFlattened()) {
DbRelationship r = getIncoming().getRelationship().getDbRelationships().get(0);
for (final DbJoin join : r.getJoins()) {
appendColumn(targetSource, join.getTargetName(), prefix + join.getTargetName());
}
}
ClassDescriptor descriptor = resolver.getDescriptor();
descriptor.visitAllProperties(new PropertyVisitor() {
public boolean visitAttribute(AttributeProperty property) {
String target = property.getAttribute().getDbAttributePath();
if (!property.getAttribute().isLazy()) {
appendColumn(targetSource, target, prefix + target);
}
return true;
}
public boolean visitToMany(ToManyProperty property) {
return visitRelationship(property);
}
public boolean visitToOne(ToOneProperty property) {
return visitRelationship(property);
}
private boolean visitRelationship(ArcProperty arc) {
DbRelationship dbRel = arc.getRelationship().getDbRelationships().get(0);
for (DbAttribute attribute : dbRel.getSourceAttributes()) {
String target = attribute.getName();
appendColumn(targetSource, target, prefix + target);
}
return true;
}
});
// append id columns ... (some may have been appended already via relationships)
for (String pkName : descriptor.getEntity().getPrimaryKeyNames()) {
appendColumn(targetSource, pkName, prefix + pkName);
}
// append inheritance discriminator columns...
for (ObjAttribute column : descriptor.getDiscriminatorColumns()) {
String target = column.getDbAttributePath();
appendColumn(targetSource, target, prefix + target);
}
int size = targetSource.size();
this.rowCapacity = (int) Math.ceil(size / 0.75);
this.columns = new ColumnDescriptor[size];
targetSource.values().toArray(columns);
}
use of org.apache.cayenne.query.PrefetchTreeNode in project cayenne by apache.
the class SelectQueryDescriptor method encodeAsXML.
@Override
public void encodeAsXML(XMLEncoder encoder, ConfigurationNodeVisitor delegate) {
encoder.start("query").attribute("name", getName()).attribute("type", type);
String rootString = null;
String rootType = null;
if (root instanceof String) {
rootType = QueryDescriptor.OBJ_ENTITY_ROOT;
rootString = root.toString();
} else if (root instanceof ObjEntity) {
rootType = QueryDescriptor.OBJ_ENTITY_ROOT;
rootString = ((ObjEntity) root).getName();
} else if (root instanceof DbEntity) {
rootType = QueryDescriptor.DB_ENTITY_ROOT;
rootString = ((DbEntity) root).getName();
} else if (root instanceof Procedure) {
rootType = QueryDescriptor.PROCEDURE_ROOT;
rootString = ((Procedure) root).getName();
} else if (root instanceof Class<?>) {
rootType = QueryDescriptor.JAVA_CLASS_ROOT;
rootString = ((Class<?>) root).getName();
}
if (rootType != null) {
encoder.attribute("root", rootType).attribute("root-name", rootString);
}
// print properties
encodeProperties(encoder);
// encode qualifier
if (qualifier != null) {
encoder.start("qualifier").nested(qualifier, delegate).end();
}
// encode orderings
encoder.nested(orderings, delegate);
PrefetchTreeNode prefetchTree = new PrefetchTreeNode();
for (String prefetchPath : prefetchesMap.keySet()) {
PrefetchTreeNode node = prefetchTree.addPath(prefetchPath);
node.setSemantics(prefetchesMap.get(prefetchPath));
node.setPhantom(false);
}
encoder.nested(prefetchTree, delegate);
delegate.visitQuery(this);
encoder.end();
}
use of org.apache.cayenne.query.PrefetchTreeNode in project cayenne by apache.
the class SQLTemplateDescriptor method encodeAsXML.
@Override
public void encodeAsXML(XMLEncoder encoder, ConfigurationNodeVisitor delegate) {
encoder.start("query").attribute("name", getName()).attribute("type", type);
String rootString = null;
String rootType = null;
if (root instanceof String) {
rootType = QueryDescriptor.OBJ_ENTITY_ROOT;
rootString = root.toString();
} else if (root instanceof ObjEntity) {
rootType = QueryDescriptor.OBJ_ENTITY_ROOT;
rootString = ((ObjEntity) root).getName();
} else if (root instanceof DbEntity) {
rootType = QueryDescriptor.DB_ENTITY_ROOT;
rootString = ((DbEntity) root).getName();
} else if (root instanceof Procedure) {
rootType = QueryDescriptor.PROCEDURE_ROOT;
rootString = ((Procedure) root).getName();
} else if (root instanceof Class<?>) {
rootType = QueryDescriptor.JAVA_CLASS_ROOT;
rootString = ((Class<?>) root).getName();
} else if (root instanceof DataMap) {
rootType = QueryDescriptor.DATA_MAP_ROOT;
rootString = ((DataMap) root).getName();
}
if (rootType != null) {
encoder.attribute("root", rootType).attribute("root-name", rootString);
}
// print properties
encodeProperties(encoder);
// encode default SQL
if (sql != null) {
encoder.start("sql").cdata(sql, true).end();
}
// encode adapter SQL
if (adapterSql != null && !adapterSql.isEmpty()) {
// sorting entries by adapter name
TreeSet<String> keys = new TreeSet<>(adapterSql.keySet());
for (String key : keys) {
String value = adapterSql.get(key);
if (key != null && value != null) {
String sql = value.trim();
if (sql.length() > 0) {
encoder.start("sql").attribute("adapter-class", key).cdata(sql, true).end();
}
}
}
}
PrefetchTreeNode prefetchTree = new PrefetchTreeNode();
for (Map.Entry<String, Integer> entry : prefetchesMap.entrySet()) {
PrefetchTreeNode node = prefetchTree.addPath(entry.getKey());
node.setSemantics(entry.getValue());
node.setPhantom(false);
}
encoder.nested(prefetchTree, delegate);
delegate.visitQuery(this);
encoder.end();
}
use of org.apache.cayenne.query.PrefetchTreeNode in project cayenne by apache.
the class PrefetchProcessorTreeBuilderIT method testBuildTreeNoPrefetches.
@Test
public void testBuildTreeNoPrefetches() {
final ClassDescriptor descriptor = resolver.getClassDescriptor("Artist");
List<DataRow> dataRows = new ArrayList<>();
dataRows.add(new DataRow(4));
dataRows.add(new DataRow(4));
QueryMetadata metadata = new MockQueryMetadata() {
@Override
public ClassDescriptor getClassDescriptor() {
return descriptor;
}
@Override
public ObjEntity getObjEntity() {
return descriptor.getEntity();
}
@Override
public DbEntity getDbEntity() {
return getObjEntity().getDbEntity();
}
@Override
public DataMap getDataMap() {
return getObjEntity().getDataMap();
}
@Override
public boolean isRefreshingObjects() {
return true;
}
@Override
public boolean isResolvingInherited() {
return true;
}
};
PrefetchTreeNode tree = new PrefetchTreeNode();
HierarchicalObjectResolver resolver = new HierarchicalObjectResolver(context, metadata);
PrefetchProcessorTreeBuilder builder = new PrefetchProcessorTreeBuilder(resolver, dataRows, new HashMap<>());
PrefetchProcessorNode processingTree = builder.buildTree(tree);
assertTrue(processingTree.getChildren().isEmpty());
assertFalse(processingTree.isPhantom());
assertFalse(processingTree.isPartitionedByParent());
assertTrue(processingTree.isDisjointPrefetch());
assertSame(dataRows, processingTree.getDataRows());
assertSame(descriptor.getEntity(), processingTree.getResolver().getEntity());
assertNull(processingTree.getIncoming());
}
Aggregations