/** * 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.openejb.test.entity.cmr; import org.apache.openejb.test.entity.cmr.onetomany.ArtistLocal; import org.apache.openejb.test.entity.cmr.onetomany.ArtistLocalHome; import org.apache.openejb.test.entity.cmr.onetomany.SongLocal; import org.apache.openejb.test.entity.cmr.onetomany.SongLocalHome; import javax.ejb.CreateException; import javax.ejb.FinderException; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.Arrays; import java.util.ConcurrentModificationException; import java.util.HashSet; import java.util.Iterator; import java.util.Set; /** * @version $Revision$ $Date$ */ @SuppressWarnings("UnusedDeclaration") public class OneToManyTests extends AbstractCMRTest { private ArtistLocalHome artistLocalHome; private SongLocalHome songLocalHome; public OneToManyTests() { super("OneToMany."); } protected void setUp() throws Exception { super.setUp(); artistLocalHome = (ArtistLocalHome) initialContext.lookup("client/tests/entity/cmr/oneToMany/ArtistLocal"); songLocalHome = (SongLocalHome) initialContext.lookup("client/tests/entity/cmr/oneToMany/SongLocal"); } public void test00_AGetBExistingAB() throws Exception { resetDB(); beginTransaction(); try { final ArtistLocal artist = findArtist(1); final Set bSet = artist.getPerformed(); assertEquals(2, bSet.size()); for (final Object value : bSet) { final SongLocal song = (SongLocal) value; if (song.getId().equals(11)) { assertEquals("value11", song.getName()); } else if (song.getId().equals(22)) { assertEquals("value22", song.getName()); } else { fail(); } } } finally { completeTransaction(); } } public void test01_BGetAExistingAB() throws Exception { resetDB(); beginTransaction(); try { SongLocal song = findSong(11); ArtistLocal artist = song.getPerformer(); assertNotNull(artist); assertEquals(new Integer(1), artist.getId()); assertEquals("value1", artist.getName()); song = findSong(22); artist = song.getPerformer(); assertNotNull(artist); assertEquals(new Integer(1), artist.getId()); assertEquals("value1", artist.getName()); } finally { completeTransaction(); } } public void test02_ASetBDropExisting() throws Exception { resetDB(); beginTransaction(); try { final ArtistLocal artist = findArtist(1); artist.setPerformed(new HashSet<SongLocal>()); } finally { completeTransaction(); } assertUnlinked(1); } public void test03_BSetADropExisting() throws Exception { resetDB(); beginTransaction(); try { SongLocal song = findSong(11); song.setPerformer(null); song = findSong(22); song.setPerformer(null); } finally { completeTransaction(); } assertUnlinked(1); } public void test04_ASetBNewAB() throws Exception { resetDB(); beginTransaction(); try { final ArtistLocal artist = findArtist(2); final SongLocal song = findSong(22); final Set<SongLocal> songSets = new HashSet<SongLocal>(); songSets.add(song); artist.setPerformed(songSets); } finally { completeTransaction(); } assertLinked(2, 22); } public void test05_BSetANewAB() throws Exception { resetDB(); beginTransaction(); try { final ArtistLocal artist = findArtist(2); final SongLocal song = findSong(22); song.setPerformer(artist); } finally { completeTransaction(); } assertLinked(2, 22); } public void test06_ASetBExistingBNewA() throws Exception { resetDB(); beginTransaction(); try { final ArtistLocal artist = findArtist(2); final SongLocal song = findSong(11); final Set<SongLocal> songSets = artist.getPerformed(); songSets.add(song); } finally { completeTransaction(); } assertLinked(2, 11); } public void test07_BSetAExistingBNewA() throws Exception { resetDB(); beginTransaction(); try { final ArtistLocal artist = findArtist(2); final SongLocal song = findSong(11); song.setPerformer(artist); } finally { completeTransaction(); } assertLinked(2, 11); } public void test08_ASetBExistingANewB() throws Exception { resetDB(); beginTransaction(); try { final ArtistLocal artist = findArtist(1); final SongLocal song = createSong(33); final Set<SongLocal> songSets = artist.getPerformed(); songSets.add(song); } finally { completeTransaction(); } assertLinked(1, 11, 22, 33); } public void test09_BSetAExistingANewB() throws Exception { resetDB(); beginTransaction(); try { final ArtistLocal artist = findArtist(1); final SongLocal song = createSong(33); song.setPerformer(artist); } finally { completeTransaction(); } assertLinked(1, 11, 22, 33); } public void test10_RemoveRelationships() throws Exception { resetDB(); beginTransaction(); try { final SongLocal song = findSong(11); final ArtistLocal artist = song.getPerformer(); final Set<SongLocal> songs = artist.getPerformed(); assertTrue(songs.contains(song)); song.remove(); assertFalse(songs.contains(song)); } finally { completeTransaction(); } assertLinked(1, 22); assertUnlinked(2); } // uncomment when cmp to cmr is supported public void TODO_testCMPMappedToForeignKeyColumn() throws Exception { resetDB(); beginTransaction(); try { final SongLocal song = findSong(11); final Integer field3 = song.getBpm(); assertEquals(song.getPerformer().getPrimaryKey(), field3); } finally { completeTransaction(); } } // uncomment when cmp to cmr is supported public void TODO_testSetCMPMappedToForeignKeyColumn() throws Exception { resetDB(); beginTransaction(); try { final SongLocal song = findSong(11); song.setBpm(2); final ArtistLocal artist = song.getPerformer(); assertEquals(new Integer(2), artist.getId()); assertEquals("value2", artist.getName()); } finally { completeTransaction(); } } public void test11_Delete() throws Exception { resetDB(); beginTransaction(); try { final ArtistLocal artist = findArtist(1); artist.setPerformed(new HashSet<SongLocal>()); final Set<SongLocal> songs = artist.getComposed(); final Set<SongLocal> bsCopies = new HashSet<SongLocal>(songs); assertSame(songs, artist.getComposed()); artist.remove(); assertTrue("CMR collection is not empty " + System.identityHashCode(songs), songs.isEmpty()); for (final SongLocal songLocal : bsCopies) { assertNull(songLocal.getComposer()); } } finally { completeTransaction(); } final Connection c = ds.getConnection(); final Statement s = c.createStatement(); final ResultSet rs = s.executeQuery("SELECT COUNT(*) FROM Song"); assertTrue(rs.next()); assertEquals(2, rs.getInt(1)); rs.close(); s.close(); c.close(); } public void test12_CascadeDelete() throws Exception { resetDB(); beginTransaction(); try { final ArtistLocal artist = findArtist(1); final Set<SongLocal> songs = artist.getPerformed(); assertFalse(songs.isEmpty()); artist.remove(); assertTrue(songs.isEmpty()); } finally { completeTransaction(); } final Connection c = ds.getConnection(); final Statement s = c.createStatement(); final ResultSet rs = s.executeQuery("SELECT COUNT(*) FROM Song"); assertTrue(rs.next()); assertEquals(0, rs.getInt(1)); rs.close(); s.close(); c.close(); } public void testIllegalCmrCollectionArgument() throws Exception { resetDB(); beginTransaction(); try { final ArtistLocal artist = findArtist(new Integer(1)); final Set songs = artist.getComposed(); try { songs.add(new Object()); fail("expected games.add(new Object()) to throw an IllegalArgumentException"); } catch (final IllegalArgumentException ignored) { } try { songs.addAll(Arrays.asList(new Object())); fail("expected games.addAll(Arrays.asList(new Object())) to throw an IllegalArgumentException"); } catch (final IllegalArgumentException ignored) { } } finally { completeTransaction(); } } public void testModifyCmrCollectionOusideTx() throws Exception { resetDB(); beginTransaction(); Set songs; SongLocal newSong; try { final ArtistLocal artist = findArtist(new Integer(1)); newSong = createSong(new Integer(33)); songs = artist.getComposed(); } finally { completeTransaction(); } // CMR collections should still be readable assertFalse(songs.isEmpty()); assertEquals(2, songs.size()); for (final Iterator iter = songs.iterator(); iter.hasNext(); ) { final SongLocal song = (SongLocal) iter.next(); if (song.getId().equals(new Integer(11))) { assertEquals("value11", song.getName()); } else if (song.getId().equals(new Integer(22))) { assertEquals("value22", song.getName()); } else { fail(); } } // But CMR collections should not be modifiable try { songs.add(newSong); fail("expected songs.add(newSong) to throw an IllegalStateException"); } catch (final IllegalStateException ignored) { } try { songs.addAll(Arrays.asList(newSong)); fail("expected songs.addAll(Arrays.asList(newSong)) to throw an IllegalStateException"); } catch (final IllegalStateException ignored) { } try { songs.remove(newSong); fail("expected songs.remove(newSong) to throw an IllegalStateException"); } catch (final IllegalStateException ignored) { } try { songs.removeAll(Arrays.asList(newSong)); fail("expected songs.removeAll(Arrays.asList(newSong)) to throw an IllegalStateException"); } catch (final IllegalStateException ignored) { } final Iterator iterator = songs.iterator(); try { iterator.remove(); fail("expected iterator.remove() to throw an ConcurrentModificationException"); } catch (final ConcurrentModificationException ignored) { } } public void testModifyCmrCollectionInNewTx() throws Exception { resetDB(); beginTransaction(); Set songs; SongLocal newSong; try { final ArtistLocal artist = findArtist(new Integer(1)); newSong = createSong(new Integer(33)); songs = artist.getComposed(); } finally { completeTransaction(); } beginTransaction(); try { // CMR collections should still be readable assertFalse(songs.isEmpty()); assertEquals(2, songs.size()); for (final Iterator iter = songs.iterator(); iter.hasNext(); ) { final SongLocal song = (SongLocal) iter.next(); if (song.getId().equals(new Integer(11))) { assertEquals("value11", song.getName()); } else if (song.getId().equals(new Integer(22))) { assertEquals("value22", song.getName()); } else { fail(); } } // But CMR collections should not be modifiable try { songs.add(newSong); fail("expected songs.add(newSong) to throw an IllegalStateException"); } catch (final IllegalStateException ignored) { } try { songs.addAll(Arrays.asList(newSong)); fail("expected songs.addAll(Arrays.asList(newSong)) to throw an IllegalStateException"); } catch (final IllegalStateException ignored) { } try { songs.remove(newSong); fail("expected songs.remove(newSong) to throw an IllegalStateException"); } catch (final IllegalStateException ignored) { } try { songs.removeAll(Arrays.asList(newSong)); fail("expected songs.removeAll(Arrays.asList(newSong)) to throw an IllegalStateException"); } catch (final IllegalStateException ignored) { } final Iterator iterator = songs.iterator(); try { iterator.remove(); fail("expected iterator.remove() to throw an ConcurrentModificationException"); } catch (final ConcurrentModificationException ignored) { } } finally { completeTransaction(); } } public void testIteratorConcurrentModification() throws Exception { resetDB(); beginTransaction(); try { final ArtistLocal artist = findArtist(new Integer(1)); final SongLocal song = findSong(new Integer(11)); final Set songs = artist.getComposed(); assertFalse(songs.isEmpty()); assertEquals(2, songs.size()); final Iterator iterator = songs.iterator(); songs.remove(song); assertEquals(1, songs.size()); try { iterator.next(); fail("expected iterator.next() to throw an ConcurrentModificationException"); } catch (final ConcurrentModificationException ignored) { } } finally { completeTransaction(); } } public void testIteratorAndRemove() throws Exception { resetDB(); beginTransaction(); try { final ArtistLocal artist = findArtist(new Integer(1)); final SongLocal song = findSong(new Integer(11)); final Set games = artist.getComposed(); assertFalse(games.isEmpty()); assertEquals(2, games.size()); final Iterator iterator = games.iterator(); assertTrue(games.contains(song)); artist.remove(); assertFalse(games.contains(song)); assertEquals(0, games.size()); try { iterator.next(); fail("expected iterator.next() to throw an ConcurrentModificationException"); } catch (final ConcurrentModificationException ignored) { } } finally { completeTransaction(); } } private ArtistLocal createArtist(final int songId) throws CreateException { final ArtistLocal artist = artistLocalHome.create(songId); artist.setName("value" + songId); return artist; } private ArtistLocal findArtist(final int artistId) throws FinderException { return artistLocalHome.findByPrimaryKey(artistId); } private SongLocal createSong(final int songId) throws CreateException { final SongLocal song = songLocalHome.create(songId); song.setName("value" + songId); return song; } private SongLocal findSong(final int songId) throws FinderException { return songLocalHome.findByPrimaryKey(songId); } private void assertLinked(final int artistId, final int... songIds) throws Exception { final Connection c = ds.getConnection(); final Statement s = c.createStatement(); ResultSet rs = s.executeQuery("SELECT name FROM Artist WHERE id = " + artistId); assertTrue(rs.next()); assertEquals("value" + artistId, rs.getString("name")); close(rs); // assert that there we are looking for the same number of linked beans rs = s.executeQuery("SELECT COUNT(*) FROM Song WHERE performer_id = 1"); assertTrue(rs.next()); assertEquals(songIds.length, rs.getInt(1)); rs.close(); // assert each of the listed b pks is linked to a for (final int songId : songIds) { rs = s.executeQuery("SELECT name, performer_id FROM Song WHERE id = " + songId); assertTrue(rs.next()); assertEquals("value" + songId, rs.getString("name")); assertEquals(artistId, rs.getInt("performer_id")); close(rs); } close(s); close(c); } private void assertUnlinked(final int aPk) throws Exception { final Connection c = ds.getConnection(); final Statement s = c.createStatement(); final ResultSet rs = s.executeQuery("SELECT COUNT(*) FROM Song WHERE performer_id = " + aPk); assertTrue(rs.next()); assertEquals(0, rs.getInt(1)); close(rs); close(s); close(c); } private synchronized void resetDB() throws Exception { final Connection connection = ds.getConnection(); Statement statement = null; try { statement = connection.createStatement(); try { statement.execute("DELETE FROM Artist"); } catch (final SQLException ignored) { } try { statement.execute("DELETE FROM Song"); } catch (final SQLException ignored) { } } finally { close(statement); close(connection); } final ArtistLocal artist1 = createArtist(1); createArtist(2); final SongLocal song1 = createSong(11); final SongLocal song2 = createSong(22); song1.setPerformer(artist1); song2.setPerformer(artist1); song1.setComposer(artist1); song2.setComposer(artist1); } protected void dump() throws SQLException { dumpTable(ds, "Artist"); dumpTable(ds, "Song"); } }