/*****************************************************************
* 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.cayenne.access;
import org.apache.cayenne.Cayenne;
import org.apache.cayenne.DataChannel;
import org.apache.cayenne.DataObject;
import org.apache.cayenne.DataRow;
import org.apache.cayenne.ObjectContext;
import org.apache.cayenne.ObjectId;
import org.apache.cayenne.PersistenceState;
import org.apache.cayenne.Persistent;
import org.apache.cayenne.configuration.server.ServerRuntime;
import org.apache.cayenne.di.Inject;
import org.apache.cayenne.query.SelectQuery;
import org.apache.cayenne.test.jdbc.DBHelper;
import org.apache.cayenne.test.jdbc.TableHelper;
import org.apache.cayenne.testdo.testmap.Artist;
import org.apache.cayenne.testdo.testmap.Painting;
import org.apache.cayenne.unit.di.DataChannelInterceptor;
import org.apache.cayenne.unit.di.UnitTestClosure;
import org.apache.cayenne.unit.di.server.CayenneProjects;
import org.apache.cayenne.unit.di.server.ServerCase;
import org.apache.cayenne.unit.di.server.UseServerRuntime;
import org.junit.Before;
import org.junit.Test;
import java.sql.Types;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import static org.junit.Assert.*;
@UseServerRuntime(CayenneProjects.TESTMAP_PROJECT)
public class NestedDataContextReadIT extends ServerCase {
@Inject
private ServerRuntime runtime;
@Inject
private DataContext context;
@Inject
private DataChannelInterceptor queryInterceptor;
@Inject
private DBHelper dbHelper;
private TableHelper tArtist;
private TableHelper tPainting;
@Before
public void setUp() throws Exception {
tArtist = new TableHelper(dbHelper, "ARTIST");
tArtist.setColumns("ARTIST_ID", "ARTIST_NAME");
tPainting = new TableHelper(dbHelper, "PAINTING");
tPainting.setColumns(
"PAINTING_ID",
"PAINTING_TITLE",
"ARTIST_ID",
"ESTIMATED_PRICE").setColumnTypes(
Types.INTEGER,
Types.VARCHAR,
Types.BIGINT,
Types.DECIMAL);
}
private void createArtistsDataSet() throws Exception {
tArtist.insert(33001, "artist1");
tArtist.insert(33002, "artist2");
tArtist.insert(33003, "artist3");
tArtist.insert(33004, "artist4");
}
private void createRelationshipDataSet() throws Exception {
tArtist.insert(33001, "artist1");
tArtist.insert(33002, "artist2");
tArtist.insert(33003, "artist3");
tArtist.insert(33004, "artist4");
tPainting.insert(33001, "P_artist1", 33001, 3000);
tPainting.insert(33002, "P_artist2", 33002, 3000);
tPainting.insert(33003, "P_artist3", 33003, 3000);
tPainting.insert(33004, "P_artist4", 33004, 3000);
tPainting.insert(33005, "P_artist5", null, 3000);
}
private void createPrefetchingDataSet() throws Exception {
tArtist.insert(33001, "artist1");
tArtist.insert(33002, "artist2");
tPainting.insert(33001, "P_artist1", 33001, 3000);
tPainting.insert(33006, "P_artist6", 33001, 3000);
}
@Test
public void testCreateChildDataContext() {
context.setValidatingObjectsOnCommit(true);
ObjectContext child1 = runtime.newContext(context);
assertNotNull(child1);
assertSame(context, child1.getChannel());
assertTrue(((DataContext) child1).isValidatingObjectsOnCommit());
context.setValidatingObjectsOnCommit(false);
ObjectContext child2 = runtime.newContext(context);
assertNotNull(child2);
assertSame(context, child2.getChannel());
assertFalse(((DataContext) child2).isValidatingObjectsOnCommit());
// second level of nesting
ObjectContext child21 = runtime.newContext((DataChannel) child2);
assertNotNull(child21);
assertSame(child2, child21.getChannel());
assertFalse(((DataContext) child2).isValidatingObjectsOnCommit());
}
@Test
public void testSelect() throws Exception {
createArtistsDataSet();
ObjectContext child = runtime.newContext(context);
// test how different object states appear in the child on select
Persistent _new = context.newObject(Artist.class);
Persistent hollow = Cayenne.objectForPK(context, Artist.class, 33001);
context.invalidateObjects(hollow);
DataObject committed = Cayenne.objectForPK(context, Artist.class, 33002);
Artist modified = Cayenne.objectForPK(context, Artist.class, 33003);
modified.setArtistName("MODDED");
DataObject deleted = Cayenne.objectForPK(context, Artist.class, 33004);
context.deleteObjects(deleted);
assertEquals(PersistenceState.HOLLOW, hollow.getPersistenceState());
assertEquals(PersistenceState.COMMITTED, committed.getPersistenceState());
assertEquals(PersistenceState.MODIFIED, modified.getPersistenceState());
assertEquals(PersistenceState.DELETED, deleted.getPersistenceState());
assertEquals(PersistenceState.NEW, _new.getPersistenceState());
List<Artist> objects = child.performQuery(new SelectQuery(Artist.class));
assertEquals("All but NEW object must have been included", 4, objects.size());
Iterator<?> it = objects.iterator();
for (Artist next : objects) {
assertEquals(PersistenceState.COMMITTED, next.getPersistenceState());
int id = Cayenne.intPKForObject(next);
if (id == 33003) {
assertEquals("MODDED", next.getArtistName());
}
}
}
@Test
public void testPageableSelect() throws Exception {
createArtistsDataSet();
ObjectContext child = runtime.newContext(context);
SelectQuery<Artist> query = SelectQuery.query(Artist.class);
query.addOrdering(Artist.ARTIST_NAME.desc());
query.setPageSize(1);
IncrementalFaultList<Artist> records = (IncrementalFaultList) child.performQuery(query);
assertEquals(4, records.size());
assertEquals(1, records.getPageSize());
}
@Test
public void testReadToOneRelationship() throws Exception {
createRelationshipDataSet();
final ObjectContext child = runtime.newContext(context);
// test how different object states appear in the child on select
Painting hollowTargetSrc = Cayenne.objectForPK(context, Painting.class, 33001);
Artist hollowTarget = hollowTargetSrc.getToArtist();
Painting modifiedTargetSrc = Cayenne.objectForPK(context, Painting.class, 33002);
Artist modifiedTarget = modifiedTargetSrc.getToArtist();
modifiedTarget.setArtistName("M1");
final Painting deletedTargetSrc = Cayenne.objectForPK(
context,
Painting.class,
33003);
Artist deletedTarget = deletedTargetSrc.getToArtist();
deletedTargetSrc.setToArtist(null);
context.deleteObjects(deletedTarget);
Painting committedTargetSrc = Cayenne.objectForPK(context, Painting.class, 33004);
Artist committedTarget = committedTargetSrc.getToArtist();
committedTarget.getArtistName();
final Painting newTargetSrc = Cayenne.objectForPK(context, Painting.class, 33005);
Artist newTarget = context.newObject(Artist.class);
newTarget.setArtistName("N1");
newTargetSrc.setToArtist(newTarget);
assertEquals(PersistenceState.COMMITTED, hollowTargetSrc.getPersistenceState());
assertEquals(PersistenceState.COMMITTED, modifiedTargetSrc.getPersistenceState());
assertEquals(PersistenceState.MODIFIED, deletedTargetSrc.getPersistenceState());
assertEquals(PersistenceState.COMMITTED, committedTargetSrc.getPersistenceState());
assertEquals(PersistenceState.MODIFIED, newTargetSrc.getPersistenceState());
assertEquals(PersistenceState.HOLLOW, hollowTarget.getPersistenceState());
assertEquals(PersistenceState.MODIFIED, modifiedTarget.getPersistenceState());
assertEquals(PersistenceState.DELETED, deletedTarget.getPersistenceState());
assertEquals(PersistenceState.COMMITTED, committedTarget.getPersistenceState());
assertEquals(PersistenceState.NEW, newTarget.getPersistenceState());
// run an ordered query, so we can address specific objects directly by index
SelectQuery q = new SelectQuery(Painting.class);
q.addOrdering(Painting.PAINTING_TITLE.asc());
final List<?> childSources = child.performQuery(q);
assertEquals(5, childSources.size());
queryInterceptor.runWithQueriesBlocked(new UnitTestClosure() {
public void execute() {
Painting childHollowTargetSrc = (Painting) childSources.get(0);
assertSame(child, childHollowTargetSrc.getObjectContext());
Artist childHollowTarget = childHollowTargetSrc.getToArtist();
assertNotNull(childHollowTarget);
assertEquals(
PersistenceState.HOLLOW,
childHollowTarget.getPersistenceState());
assertSame(child, childHollowTarget.getObjectContext());
Artist childModifiedTarget = ((Painting) childSources.get(1))
.getToArtist();
assertEquals(
PersistenceState.COMMITTED,
childModifiedTarget.getPersistenceState());
assertSame(child, childModifiedTarget.getObjectContext());
assertEquals("M1", childModifiedTarget.getArtistName());
Painting childDeletedTargetSrc = (Painting) childSources.get(2);
// make sure we got the right object...
assertEquals(
deletedTargetSrc.getObjectId(),
childDeletedTargetSrc.getObjectId());
Artist childDeletedTarget = childDeletedTargetSrc.getToArtist();
assertNull(childDeletedTarget);
Artist childCommittedTarget = ((Painting) childSources.get(3))
.getToArtist();
assertEquals(
PersistenceState.COMMITTED,
childCommittedTarget.getPersistenceState());
assertSame(child, childCommittedTarget.getObjectContext());
Painting childNewTargetSrc = (Painting) childSources.get(4);
// make sure we got the right object...
assertEquals(newTargetSrc.getObjectId(), childNewTargetSrc.getObjectId());
Artist childNewTarget = childNewTargetSrc.getToArtist();
assertNotNull(childNewTarget);
assertEquals(
PersistenceState.COMMITTED,
childNewTarget.getPersistenceState());
assertSame(child, childNewTarget.getObjectContext());
assertEquals("N1", childNewTarget.getArtistName());
}
});
}
@Test
public void testPrefetchingToOne() throws Exception {
createPrefetchingDataSet();
final ObjectContext child = runtime.newContext(context);
final ObjectId prefetchedId = new ObjectId(
"Artist",
Artist.ARTIST_ID_PK_COLUMN,
new Integer(33001));
SelectQuery q = new SelectQuery(Painting.class);
q.addOrdering(Painting.PAINTING_TITLE.asc());
q.addPrefetch(Painting.TO_ARTIST.disjoint());
final List<?> results = child.performQuery(q);
// blockQueries();
queryInterceptor.runWithQueriesBlocked(new UnitTestClosure() {
public void execute() {
assertEquals(2, results.size());
Iterator<?> it = results.iterator();
while (it.hasNext()) {
Painting o = (Painting) it.next();
assertEquals(PersistenceState.COMMITTED, o.getPersistenceState());
assertSame(child, o.getObjectContext());
Artist o1 = o.getToArtist();
assertNotNull(o1);
assertEquals(PersistenceState.COMMITTED, o1.getPersistenceState());
assertSame(child, o1.getObjectContext());
assertEquals(prefetchedId, o1.getObjectId());
}
}
});
}
@Test
public void testPrefetchingToMany() throws Exception {
createPrefetchingDataSet();
final ObjectContext child = runtime.newContext(context);
SelectQuery q = new SelectQuery(Artist.class);
q.addOrdering(Artist.ARTIST_NAME.asc());
q.addPrefetch(Artist.PAINTING_ARRAY.disjoint());
final List<?> results = child.performQuery(q);
queryInterceptor.runWithQueriesBlocked(new UnitTestClosure() {
public void execute() {
Artist o1 = (Artist) results.get(0);
assertEquals(PersistenceState.COMMITTED, o1.getPersistenceState());
assertSame(child, o1.getObjectContext());
List<?> children1 = o1.getPaintingArray();
assertEquals(2, children1.size());
Iterator<?> it = children1.iterator();
while (it.hasNext()) {
Painting o = (Painting) it.next();
assertEquals(PersistenceState.COMMITTED, o.getPersistenceState());
assertSame(child, o.getObjectContext());
assertEquals(o1, o.getToArtist());
}
Artist o2 = (Artist) results.get(1);
assertEquals(PersistenceState.COMMITTED, o2.getPersistenceState());
assertSame(child, o2.getObjectContext());
List<?> children2 = o2.getPaintingArray();
assertEquals(0, children2.size());
}
});
}
@Test
public void testObjectFromDataRow() throws Exception {
DataContext childContext = (DataContext) runtime.newContext(context);
DataRow row = new DataRow(8);
row.put("ARTIST_ID", 5l);
row.put("ARTIST_NAME", "A");
row.put("DATE_OF_BIRTH", new Date());
Artist artist = childContext.objectFromDataRow(Artist.class, row);
assertNotNull(artist);
assertEquals(PersistenceState.COMMITTED, artist.getPersistenceState());
assertSame(childContext, artist.getObjectContext());
Object parentArtist = context.getObjectStore().getNode(artist.getObjectId());
assertNotNull(parentArtist);
assertNotSame(artist, parentArtist);
}
}