Search in sources :

Example 6 with ArcProperty

use of org.apache.cayenne.reflect.ArcProperty in project cayenne by apache.

the class FlattenedRelationshipInContextIT method testIsToOneTargetModifiedFlattenedFault1.

@Test
public void testIsToOneTargetModifiedFlattenedFault1() throws Exception {
    createFlattenedTestDataSet();
    // fetch
    List<?> ft3s = context.performQuery(new SelectQuery(FlattenedTest3.class));
    assertEquals(1, ft3s.size());
    FlattenedTest3 ft3 = (FlattenedTest3) ft3s.get(0);
    // mark as dirty for the purpose of the test...
    ft3.setPersistenceState(PersistenceState.MODIFIED);
    assertTrue(ft3.readPropertyDirectly("toFT1") instanceof Fault);
    // test that checking for modifications does not trigger a fault, and generally
    // works well
    ClassDescriptor d = context.getEntityResolver().getClassDescriptor("FlattenedTest3");
    ArcProperty flattenedRel = (ArcProperty) d.getProperty("toFT1");
    ObjectDiff diff = context.getObjectStore().registerDiff(ft3.getObjectId(), null);
    assertFalse(DataRowUtils.isToOneTargetModified(flattenedRel, ft3, diff));
    assertTrue(ft3.readPropertyDirectly("toFT1") instanceof Fault);
}
Also used : SelectQuery(org.apache.cayenne.query.SelectQuery) FlattenedTest3(org.apache.cayenne.testdo.relationships_flattened.FlattenedTest3) ArcProperty(org.apache.cayenne.reflect.ArcProperty) ClassDescriptor(org.apache.cayenne.reflect.ClassDescriptor) Fault(org.apache.cayenne.Fault) Test(org.junit.Test)

Example 7 with ArcProperty

use of org.apache.cayenne.reflect.ArcProperty in project cayenne by apache.

the class EntityResolverClassDescriptorIT method testArcProperties.

@Test
public void testArcProperties() {
    EntityResolver resolver = runtime.getDataDomain().getEntityResolver();
    resolver.getClassDescriptorMap().clearDescriptors();
    ClassDescriptor descriptor = resolver.getClassDescriptor("MtTable1");
    assertNotNull(descriptor);
    PropertyDescriptor p = descriptor.getProperty(MtTable1.TABLE2ARRAY.getName());
    assertTrue(p instanceof ArcProperty);
    ClassDescriptor target = ((ArcProperty) p).getTargetDescriptor();
    assertNotNull(target);
    assertSame(resolver.getClassDescriptor("MtTable2"), target);
    assertNotNull(((ArcProperty) p).getComplimentaryReverseArc());
    assertEquals(MtTable2.TABLE1.getName(), ((ArcProperty) p).getComplimentaryReverseArc().getName());
}
Also used : ArcProperty(org.apache.cayenne.reflect.ArcProperty) ClassDescriptor(org.apache.cayenne.reflect.ClassDescriptor) PropertyDescriptor(org.apache.cayenne.reflect.PropertyDescriptor) Test(org.junit.Test)

Example 8 with ArcProperty

use of org.apache.cayenne.reflect.ArcProperty in project cayenne by apache.

the class DefaultSelectTranslator method appendQueryColumns.

/**
 * Appends columns needed for object SelectQuery to the provided columns
 * list.
 */
<T> List<ColumnDescriptor> appendQueryColumns(final List<ColumnDescriptor> columns, SelectQuery<T> query, ClassDescriptor descriptor, final String tableAlias) {
    final Set<ColumnTracker> attributes = new HashSet<>();
    // fetched attributes include attributes that are either:
    // 
    // * class properties
    // * PK
    // * FK used in relationship
    // * joined prefetch PK
    ObjEntity oe = descriptor.getEntity();
    PropertyVisitor visitor = new PropertyVisitor() {

        public boolean visitAttribute(AttributeProperty property) {
            ObjAttribute oa = property.getAttribute();
            resetJoinStack();
            Iterator<CayenneMapEntry> dbPathIterator = oa.getDbPathIterator();
            while (dbPathIterator.hasNext()) {
                Object pathPart = dbPathIterator.next();
                if (pathPart == null) {
                    throw new CayenneRuntimeException("ObjAttribute has no component: %s", oa.getName());
                } else if (pathPart instanceof DbRelationship) {
                    DbRelationship rel = (DbRelationship) pathPart;
                    dbRelationshipAdded(rel, JoinType.LEFT_OUTER, null);
                } else if (pathPart instanceof DbAttribute) {
                    DbAttribute dbAttr = (DbAttribute) pathPart;
                    appendColumn(columns, oa, dbAttr, attributes, null, tableAlias);
                }
            }
            return true;
        }

        public boolean visitToMany(ToManyProperty property) {
            visitRelationship(property);
            return true;
        }

        public boolean visitToOne(ToOneProperty property) {
            visitRelationship(property);
            return true;
        }

        private void visitRelationship(ArcProperty property) {
            resetJoinStack();
            ObjRelationship rel = property.getRelationship();
            DbRelationship dbRel = rel.getDbRelationships().get(0);
            List<DbJoin> joins = dbRel.getJoins();
            for (DbJoin join : joins) {
                DbAttribute src = join.getSource();
                appendColumn(columns, null, src, attributes, null, tableAlias);
            }
        }
    };
    descriptor.visitAllProperties(visitor);
    // stack should be reset, because all root table attributes go with "t0"
    // table alias
    resetJoinStack();
    // add remaining needed attrs from DbEntity
    DbEntity table = oe.getDbEntity();
    for (DbAttribute dba : table.getPrimaryKeys()) {
        appendColumn(columns, null, dba, attributes, null, tableAlias);
    }
    if (query instanceof PrefetchSelectQuery) {
        // for each relationship path add PK of the target entity...
        for (String path : ((PrefetchSelectQuery) query).getResultPaths()) {
            ASTDbPath pathExp = (ASTDbPath) oe.translateToDbPath(ExpressionFactory.exp(path));
            // add joins and find terminating element
            resetJoinStack();
            PathComponent<DbAttribute, DbRelationship> lastComponent = null;
            for (PathComponent<DbAttribute, DbRelationship> component : table.resolvePath(pathExp, getPathAliases())) {
                if (component.getRelationship() != null) {
                    // do not invoke dbRelationshipAdded(), invoke
                    // pushJoin() instead. This is to prevent
                    // 'forcingDistinct' flipping to true, that will result
                    // in unneeded extra processing and sometimes in invalid
                    // results (see CAY-1979). Distinctness of each row is
                    // guaranteed by the prefetch query semantics - we
                    // include target ID in the result columns
                    getJoinStack().pushJoin(component.getRelationship(), component.getJoinType(), null);
                }
                lastComponent = component;
            }
            // process terminating element
            if (lastComponent != null) {
                DbRelationship relationship = lastComponent.getRelationship();
                if (relationship != null) {
                    String labelPrefix = pathExp.getPath();
                    DbEntity targetEntity = relationship.getTargetEntity();
                    for (DbAttribute pk : targetEntity.getPrimaryKeys()) {
                        // note that we my select a source attribute, but
                        // label it as
                        // target for simplified snapshot processing
                        appendColumn(columns, null, pk, attributes, labelPrefix + '.' + pk.getName());
                    }
                }
            }
        }
    }
    // handle joint prefetches directly attached to this query...
    if (query.getPrefetchTree() != null) {
        // perform some sort of union or sub-queries.
        for (PrefetchTreeNode prefetch : query.getPrefetchTree().getChildren()) {
            prefetch.setEntityName(oe.getName());
        }
        for (PrefetchTreeNode prefetch : query.getPrefetchTree().adjacentJointNodes()) {
            // for each prefetch add all joins plus columns from the target
            // entity
            Expression prefetchExp = ExpressionFactory.exp(prefetch.getPath());
            ASTDbPath dbPrefetch = (ASTDbPath) oe.translateToDbPath(prefetchExp);
            resetJoinStack();
            DbRelationship r = null;
            for (PathComponent<DbAttribute, DbRelationship> component : table.resolvePath(dbPrefetch, getPathAliases())) {
                r = component.getRelationship();
                dbRelationshipAdded(r, JoinType.LEFT_OUTER, null);
            }
            if (r == null) {
                throw new CayenneRuntimeException("Invalid joint prefetch '%s' for entity: %s", prefetch, oe.getName());
            }
            // add columns from the target entity, including those that are matched
            // against the FK of the source entity.
            // This is needed to determine whether optional relationships are null
            // go via target OE to make sure that Java types are mapped correctly...
            ObjRelationship targetRel = (ObjRelationship) prefetchExp.evaluate(oe);
            ObjEntity targetEntity = targetRel.getTargetEntity();
            String labelPrefix = dbPrefetch.getPath();
            PropertyVisitor prefetchVisitor = new PropertyVisitor() {

                public boolean visitAttribute(AttributeProperty property) {
                    ObjAttribute oa = property.getAttribute();
                    Iterator<CayenneMapEntry> dbPathIterator = oa.getDbPathIterator();
                    while (dbPathIterator.hasNext()) {
                        Object pathPart = dbPathIterator.next();
                        if (pathPart == null) {
                            throw new CayenneRuntimeException("ObjAttribute has no component: %s", oa.getName());
                        } else if (pathPart instanceof DbRelationship) {
                            DbRelationship rel = (DbRelationship) pathPart;
                            dbRelationshipAdded(rel, JoinType.INNER, null);
                        } else if (pathPart instanceof DbAttribute) {
                            DbAttribute dbAttr = (DbAttribute) pathPart;
                            appendColumn(columns, oa, dbAttr, attributes, labelPrefix + '.' + dbAttr.getName());
                        }
                    }
                    return true;
                }

                public boolean visitToMany(ToManyProperty property) {
                    return true;
                }

                public boolean visitToOne(ToOneProperty property) {
                    return true;
                }
            };
            ClassDescriptor prefetchClassDescriptor = entityResolver.getClassDescriptor(targetEntity.getName());
            prefetchClassDescriptor.visitAllProperties(prefetchVisitor);
            // append remaining target attributes such as keys
            DbEntity targetDbEntity = r.getTargetEntity();
            for (DbAttribute attribute : targetDbEntity.getAttributes()) {
                appendColumn(columns, null, attribute, attributes, labelPrefix + '.' + attribute.getName());
            }
        }
    }
    return columns;
}
Also used : ArcProperty(org.apache.cayenne.reflect.ArcProperty) ObjAttribute(org.apache.cayenne.map.ObjAttribute) ASTDbPath(org.apache.cayenne.exp.parser.ASTDbPath) ClassDescriptor(org.apache.cayenne.reflect.ClassDescriptor) CayenneRuntimeException(org.apache.cayenne.CayenneRuntimeException) DbAttribute(org.apache.cayenne.map.DbAttribute) ToOneProperty(org.apache.cayenne.reflect.ToOneProperty) CayenneMapEntry(org.apache.cayenne.util.CayenneMapEntry) DbEntity(org.apache.cayenne.map.DbEntity) PrefetchTreeNode(org.apache.cayenne.query.PrefetchTreeNode) HashSet(java.util.HashSet) ObjRelationship(org.apache.cayenne.map.ObjRelationship) AttributeProperty(org.apache.cayenne.reflect.AttributeProperty) PrefetchSelectQuery(org.apache.cayenne.query.PrefetchSelectQuery) ObjEntity(org.apache.cayenne.map.ObjEntity) ToManyProperty(org.apache.cayenne.reflect.ToManyProperty) Expression(org.apache.cayenne.exp.Expression) DbRelationship(org.apache.cayenne.map.DbRelationship) DbJoin(org.apache.cayenne.map.DbJoin) PropertyVisitor(org.apache.cayenne.reflect.PropertyVisitor)

Example 9 with ArcProperty

use of org.apache.cayenne.reflect.ArcProperty in project cayenne by apache.

the class ObjectContextQueryAction method interceptRelationshipQuery.

protected boolean interceptRelationshipQuery() {
    if (query instanceof RelationshipQuery) {
        RelationshipQuery relationshipQuery = (RelationshipQuery) query;
        if (!relationshipQuery.isRefreshing()) {
            if (targetContext == null && relationshipQuery.getRelationship(actingContext.getEntityResolver()).isToMany()) {
                return !DONE;
            }
            ObjectId id = relationshipQuery.getObjectId();
            Object object = actingContext.getGraphManager().getNode(id);
            if (object != null) {
                ClassDescriptor descriptor = actingContext.getEntityResolver().getClassDescriptor(id.getEntityName());
                if (!descriptor.isFault(object)) {
                    ArcProperty property = (ArcProperty) descriptor.getProperty(relationshipQuery.getRelationshipName());
                    if (!property.isFault(object)) {
                        Object related = property.readPropertyDirectly(object);
                        List result;
                        // null to-one
                        if (related == null) {
                            result = new ArrayList(1);
                        } else // to-many List
                        if (related instanceof List) {
                            result = (List) related;
                        } else // to-many Set
                        if (related instanceof Set) {
                            result = new ArrayList((Set) related);
                        } else // to-many Map
                        if (related instanceof Map) {
                            result = new ArrayList(((Map) related).values());
                        } else // non-null to-one
                        {
                            result = new ArrayList(1);
                            result.add(related);
                        }
                        this.response = new ListResponse(result);
                        return DONE;
                    }
                    /**
                     * Workaround for CAY-1183. If a Relationship query is being sent
                     * from child context, we assure that local object is not NEW and
                     * relationship - unresolved (this way exception will occur). This
                     * helps when faulting objects that were committed to parent
                     * context (this), but not to database. Checking type of context's
                     * channel is the only way to ensure that we are on the top level
                     * of context hierarchy (there might be more than one-level-deep
                     * nested contexts).
                     */
                    if (((Persistent) object).getPersistenceState() == PersistenceState.NEW && !(actingContext.getChannel() instanceof BaseContext)) {
                        this.response = new ListResponse();
                        return DONE;
                    }
                }
            }
        }
    }
    return !DONE;
}
Also used : BaseContext(org.apache.cayenne.BaseContext) ArcProperty(org.apache.cayenne.reflect.ArcProperty) Set(java.util.Set) ClassDescriptor(org.apache.cayenne.reflect.ClassDescriptor) RelationshipQuery(org.apache.cayenne.query.RelationshipQuery) ObjectId(org.apache.cayenne.ObjectId) ArrayList(java.util.ArrayList) ArrayList(java.util.ArrayList) List(java.util.List) Persistent(org.apache.cayenne.Persistent) Map(java.util.Map)

Example 10 with ArcProperty

use of org.apache.cayenne.reflect.ArcProperty 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());
            targetProperty.writeProperty(target, null, property.readProperty(source));
            return true;
        }
    });
    return target;
}
Also used : ArcProperty(org.apache.cayenne.reflect.ArcProperty) ClassDescriptor(org.apache.cayenne.reflect.ClassDescriptor) PropertyDescriptor(org.apache.cayenne.reflect.PropertyDescriptor) ObjectId(org.apache.cayenne.ObjectId) HashMap(java.util.HashMap) CayenneRuntimeException(org.apache.cayenne.CayenneRuntimeException) ArrayList(java.util.ArrayList) ToManyMapProperty(org.apache.cayenne.reflect.ToManyMapProperty) Persistent(org.apache.cayenne.Persistent) AttributeProperty(org.apache.cayenne.reflect.AttributeProperty) ToOneProperty(org.apache.cayenne.reflect.ToOneProperty) Entry(java.util.Map.Entry) ToManyProperty(org.apache.cayenne.reflect.ToManyProperty) PrefetchTreeNode(org.apache.cayenne.query.PrefetchTreeNode) Collection(java.util.Collection) HashMap(java.util.HashMap) Map(java.util.Map) PropertyVisitor(org.apache.cayenne.reflect.PropertyVisitor)

Aggregations

ArcProperty (org.apache.cayenne.reflect.ArcProperty)23 ClassDescriptor (org.apache.cayenne.reflect.ClassDescriptor)18 ToManyProperty (org.apache.cayenne.reflect.ToManyProperty)13 AttributeProperty (org.apache.cayenne.reflect.AttributeProperty)11 ToOneProperty (org.apache.cayenne.reflect.ToOneProperty)11 PropertyVisitor (org.apache.cayenne.reflect.PropertyVisitor)10 CayenneRuntimeException (org.apache.cayenne.CayenneRuntimeException)6 Persistent (org.apache.cayenne.Persistent)5 ObjRelationship (org.apache.cayenne.map.ObjRelationship)5 PropertyDescriptor (org.apache.cayenne.reflect.PropertyDescriptor)5 HashMap (java.util.HashMap)4 PrefetchTreeNode (org.apache.cayenne.query.PrefetchTreeNode)4 Test (org.junit.Test)4 ArrayList (java.util.ArrayList)3 List (java.util.List)3 Map (java.util.Map)3 ObjectId (org.apache.cayenne.ObjectId)3 DbAttribute (org.apache.cayenne.map.DbAttribute)3 DbJoin (org.apache.cayenne.map.DbJoin)3 DbRelationship (org.apache.cayenne.map.DbRelationship)3