/******************************************************************************* * Copyright (c) 2004, 2007 IBM Corporation and Cambridge Semantics Incorporated. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * File: $Source: /cvsroot/slrp/boca/com.ibm.adtech.boca.test/src/com/ibm/adtech/boca/test/client/TestUpdates.java,v $ * Created by: Rouben Meschian (<a href="mailto:rmeschi@us.ibm.com">rmeschi@us.ibm.com</a>) * Created on: 9/22/2006 * Revision: $Id: TestUpdates.java 171 2007-07-31 14:11:17Z mroy $ * * Contributors: * IBM Corporation - initial API and implementation * Cambridge Semantics Incorporated - Fork to Anzo *******************************************************************************/ package org.openanzo.test.client; import java.util.ArrayList; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import org.openanzo.client.AnzoClient; import org.openanzo.client.ClientGraph; import org.openanzo.ontologies.openanzo.NamedGraph; import org.openanzo.rdf.Constants; import org.openanzo.rdf.IAnzoGraph; import org.openanzo.rdf.INamedGraph; import org.openanzo.rdf.IStatementListener; import org.openanzo.rdf.Literal; import org.openanzo.rdf.Statement; import org.openanzo.rdf.URI; import org.openanzo.rdf.utils.StatementUtils; import org.openanzo.rdf.utils.test.Condition; import org.openanzo.rdf.utils.test.TestUtilities; import org.openanzo.test.AbstractTest; /** * This class is designed to test notifications/updates. * * @author Rouben Meschian (<a href="mailto:rmeschi@us.ibm.com">rmeschi@us.ibm.com</a>) * */ public class TestUpdates extends AbstractTest { static final URI GRAPH_URI = Constants.valueFactory.createURI("http://graph1"); static final Statement stmt1 = Constants.valueFactory.createStatement(createTestUri("subject1"), createTestUri("predicate1"), createTestUri("object1")); static final Statement stmt2 = Constants.valueFactory.createStatement(createTestUri("subject1"), createTestUri("predicate1"), createTestUri("object2")); static final Statement stmt3 = Constants.valueFactory.createStatement(createTestUri("subject3"), createTestUri("predicate3"), createTestUri("object3")); private int numRemoved1 = 0, numAdded1 = 0, numRemoved2 = 0, numAdded2 = 0, numRemoved3 = 0, numAdded3 = 0; /** * Test: * <ol> * <li>Updates among three clients.</li> * <li>Adding and removing statements to/from replica graphs.</li> * <li>Revision history access.</li> * <li>Statement listener updates.</li> * <li>Immediate replication mode.</li> * <li>Events received by IReplicationListener.</li> * <li>Closing of datasets and replica graphs.</li> * </ol> * * @throws Exception */ public void testNotificationsWithThreeClientsAndImmediateReplication() throws Exception { AnzoClient anzoClient1 = null; AnzoClient anzoClient2 = null; AnzoClient anzoClient3 = null; try { numAdded1 = numAdded2 = numAdded3 = numRemoved1 = numRemoved2 = numRemoved3 = 0; // // create DATASET SERVICE 1 (CLIENT 1) // anzoClient1 = new AnzoClient(getDefaultClientConfiguration()); anzoClient1.connect(); anzoClient1.reset(loadStatements("initialize.trig"), null); // // create DATASET SERVICE 2 (CLIENT 2) // anzoClient2 = new AnzoClient(getDefaultClientConfiguration()); anzoClient2.connect(); // // create DATASET SERVICE 3 (CLIENT 3) // anzoClient3 = new AnzoClient(getDefaultClientConfiguration()); anzoClient3.connect(); assertFalse(anzoClient1.namedGraphExists(GRAPH_URI)); assertFalse(anzoClient2.namedGraphExists(GRAPH_URI)); assertFalse(anzoClient3.namedGraphExists(GRAPH_URI)); // create graph with name GRAPH_URI ClientGraph replicaGraph1 = anzoClient1.getReplicaGraph(GRAPH_URI); assertNotNull(replicaGraph1); anzoClient1.updateRepository(); assertTrue(anzoClient1.namedGraphExists(GRAPH_URI)); assertTrue(anzoClient2.namedGraphExists(GRAPH_URI)); assertTrue(anzoClient3.namedGraphExists(GRAPH_URI)); // get existing graph with name GRAPH_URI ClientGraph replicaGraph2 = anzoClient2.getReplicaGraph(GRAPH_URI); assertNotNull(replicaGraph2); anzoClient2.updateRepository(); assertTrue(anzoClient1.namedGraphExists(GRAPH_URI)); assertTrue(anzoClient2.namedGraphExists(GRAPH_URI)); assertTrue(anzoClient3.namedGraphExists(GRAPH_URI)); // get existing graph with name GRAPH_URI ClientGraph replicaGraph3 = anzoClient3.getReplicaGraph(GRAPH_URI); assertNotNull(replicaGraph3); assertTrue(anzoClient1.namedGraphExists(GRAPH_URI)); assertTrue(anzoClient2.namedGraphExists(GRAPH_URI)); assertTrue(anzoClient3.namedGraphExists(GRAPH_URI)); anzoClient3.updateRepository(); // ADD LISTENERS TO REPLICA GRAPHS replicaGraph1.registerListener(new IStatementListener<INamedGraph>() { public void statementsRemoved(INamedGraph source, Statement... s) { numRemoved1 += s.length; } public void statementsAdded(INamedGraph source, Statement... s) { numAdded1 += s.length; } }); replicaGraph2.registerListener(new IStatementListener<INamedGraph>() { public void statementsRemoved(INamedGraph source, Statement... s) { numRemoved2 += s.length; } public void statementsAdded(INamedGraph source, Statement... s) { numAdded2 += s.length; } }); replicaGraph3.registerListener(new IStatementListener<INamedGraph>() { public void statementsRemoved(INamedGraph source, Statement... s) { numRemoved3 += s.length; } public void statementsAdded(INamedGraph source, Statement... s) { numAdded3 += s.length; } }); // ----------------------------------------------------------------- // add a statement to first graph // -make sure all graphs contain the same data // -make sure all statement listeners received events // -check revision history long currentRevision = getNamedGraphRevision(anzoClient1.getCurrentNamedGraphRevision(GRAPH_URI)); assertEquals(0, currentRevision); replicaGraph1.add(stmt1); anzoClient1.updateRepository(); assertTrue(replicaGraph1.contains(stmt1)); // check the revision has incremented currentRevision = getNamedGraphRevision(anzoClient1.getCurrentNamedGraphRevision(GRAPH_URI)); assertEquals(1, currentRevision); replicaGraph1.add(stmt2); anzoClient1.updateRepository(); assertTrue(replicaGraph1.contains(stmt2)); // check the revision has incremented currentRevision = getNamedGraphRevision(anzoClient1.getCurrentNamedGraphRevision(GRAPH_URI)); assertEquals(2, currentRevision); replicaGraph1.remove(stmt2); anzoClient1.updateRepository(); assertFalse(replicaGraph1.contains(stmt2)); // check the revision has incremented currentRevision = getNamedGraphRevision(anzoClient1.getCurrentNamedGraphRevision(GRAPH_URI)); assertEquals(3, currentRevision); IAnzoGraph localGraph1V2 = anzoClient1.getNamedGraphRevision(GRAPH_URI, 1); assertNotNull(localGraph1V2); assertTrue(localGraph1V2.contains(stmt1)); assertFalse(localGraph1V2.contains(stmt2)); TestUtilities.waitForStatement(replicaGraph2, stmt1, true); assertTrue(replicaGraph2.contains(stmt1)); TestUtilities.waitForStatement(replicaGraph2, stmt2, false); assertFalse(replicaGraph2.contains(stmt2)); TestUtilities.waitForStatement(replicaGraph3, stmt1, true); assertTrue(replicaGraph3.contains(stmt1)); TestUtilities.waitForStatement(replicaGraph3, stmt3, false); assertFalse(replicaGraph3.contains(stmt3)); // make sure both graph listeners received an update TestUtilities.waitFor(new Condition() { @Override public boolean check() { return numAdded1 >= 2; } }); assertTrue(numAdded1 >= 2); TestUtilities.waitFor(new Condition() { @Override public boolean check() { return numAdded2 >= 2; } }); assertTrue(numAdded2 >= 2); TestUtilities.waitFor(new Condition() { @Override public boolean check() { return numAdded3 >= 2; } }); assertTrue(numAdded3 >= 2); TestUtilities.waitFor(new Condition() { @Override public boolean check() { return numRemoved1 >= 1; } }); assertTrue(numRemoved1 >= 1); TestUtilities.waitFor(new Condition() { @Override public boolean check() { return numRemoved2 >= 1; } }); assertTrue(numRemoved2 >= 1); TestUtilities.waitFor(new Condition() { @Override public boolean check() { return numRemoved3 >= 1; } }); assertTrue(numRemoved3 >= 1); numAdded1 = numAdded2 = numAdded3 = numRemoved1 = numRemoved2 = numRemoved3 = 0; // ----------------------------------------------------------------- // delete all statements in a single transaction // -make sure all graphs contain the same data replicaGraph3.clear(); anzoClient3.updateRepository(); TestUtilities.waitForSize(replicaGraph1, 0); assertEquals(0, replicaGraph1.size()); TestUtilities.waitForSize(replicaGraph2, 0); assertEquals(0, replicaGraph2.size()); TestUtilities.waitForSize(replicaGraph3, 0); assertEquals(0, replicaGraph3.size()); // ------------------------------------------------------------------ // add statements to all graphs // -make sure all graphs contain the same data // -make sure all graph listeners are notified replicaGraph1.add(stmt1); replicaGraph2.add(stmt2); replicaGraph3.add(stmt3); anzoClient1.updateRepository(); anzoClient2.updateRepository(); anzoClient3.updateRepository(); TestUtilities.waitForStatement(replicaGraph1, stmt1, true); assertTrue(replicaGraph1.contains(stmt1)); TestUtilities.waitForStatement(replicaGraph2, stmt1, true); assertTrue(replicaGraph2.contains(stmt1)); TestUtilities.waitForStatement(replicaGraph3, stmt1, true); assertTrue(replicaGraph3.contains(stmt1)); TestUtilities.waitForStatement(replicaGraph1, stmt2, true); assertTrue(replicaGraph1.contains(stmt2)); TestUtilities.waitForStatement(replicaGraph2, stmt2, true); assertTrue(replicaGraph2.contains(stmt2)); TestUtilities.waitForStatement(replicaGraph3, stmt2, true); assertTrue(replicaGraph3.contains(stmt2)); TestUtilities.waitForStatement(replicaGraph1, stmt3, true); assertTrue(replicaGraph1.contains(stmt3)); TestUtilities.waitForStatement(replicaGraph2, stmt3, true); assertTrue(replicaGraph2.contains(stmt3)); TestUtilities.waitForStatement(replicaGraph3, stmt3, true); assertTrue(replicaGraph3.contains(stmt3)); // make sure all graph listeners received an update assertTrue(numAdded1 >= 1); assertTrue(numAdded2 >= 1); assertTrue(numAdded3 >= 1); numAdded1 = numAdded2 = numAdded3 = numRemoved1 = numRemoved2 = numRemoved3 = 0; // ------------------------------------------------------------------ // delete statements from all graphs // -make sure all graphs contain the same data // -make sure all statement listeners are notified replicaGraph1.remove(stmt3); replicaGraph2.remove(stmt2); replicaGraph3.remove(stmt1); anzoClient1.updateRepository(); anzoClient2.updateRepository(); anzoClient3.updateRepository(); TestUtilities.waitForSize(replicaGraph1, 0); assertEquals(0, replicaGraph1.size()); TestUtilities.waitForSize(replicaGraph2, 0); assertEquals(0, replicaGraph2.size()); TestUtilities.waitForSize(replicaGraph3, 0); assertEquals(0, replicaGraph3.size()); // make sure all statement listeners received an update assertTrue(numRemoved1 >= 1); assertTrue(numRemoved2 >= 1); assertTrue(numRemoved3 >= 1); numAdded1 = numAdded2 = numAdded3 = numRemoved1 = numRemoved2 = numRemoved3 = 0; // ----------------------------------------------------------------- // add and delete statements in a single transaction // -make sure other graphs do not change until the transaction is committed // -make sure all graphs contain the same data // -make sure all statement listeners received events anzoClient1.begin(); replicaGraph1.add(stmt2); assertTrue(replicaGraph1.contains(stmt2)); assertFalse(replicaGraph2.contains(stmt2)); assertFalse(replicaGraph3.contains(stmt2)); replicaGraph1.add(stmt3); assertTrue(replicaGraph1.contains(stmt3)); assertFalse(replicaGraph2.contains(stmt3)); assertFalse(replicaGraph3.contains(stmt3)); anzoClient1.commit(); anzoClient1.updateRepository(); TestUtilities.waitForStatement(replicaGraph2, stmt2, true); assertTrue(replicaGraph2.contains(stmt2)); assertTrue(replicaGraph2.contains(stmt2)); TestUtilities.waitForStatement(replicaGraph3, stmt2, true); assertTrue(replicaGraph3.contains(stmt2)); assertTrue(replicaGraph3.contains(stmt2)); // make sure all graph listeners received an update assertTrue(numAdded1 >= 2); assertTrue(numAdded2 >= 2); assertTrue(numAdded3 >= 2); numAdded1 = numAdded2 = numAdded3 = numRemoved1 = numRemoved2 = numRemoved3 = 0; // ----------------------------------------------------------------- // add and delete statements in multiple transactions // -make sure other graphs do not change until the transaction is committed // -make sure all graphs contain the same data // -make sure all statement listeners received events anzoClient1.begin(); replicaGraph1.clear(); anzoClient1.commit(); anzoClient1.updateRepository(); numAdded1 = numAdded2 = numAdded3 = numRemoved1 = numRemoved2 = numRemoved3 = 0; TestUtilities.waitForStatement(replicaGraph2, stmt2, false); assertFalse(replicaGraph2.contains(stmt2)); TestUtilities.waitForStatement(replicaGraph3, stmt2, false); assertFalse(replicaGraph3.contains(stmt2)); anzoClient1.begin(); replicaGraph1.add(stmt1); assertTrue(replicaGraph1.contains(stmt1)); assertFalse(replicaGraph2.contains(stmt1)); assertFalse(replicaGraph3.contains(stmt1)); replicaGraph1.add(stmt2); assertTrue(replicaGraph1.contains(stmt2)); assertFalse(replicaGraph2.contains(stmt2)); assertFalse(replicaGraph3.contains(stmt2)); anzoClient1.commit(); anzoClient1.updateRepository(); anzoClient2.begin(); replicaGraph2.add(stmt3); assertTrue(replicaGraph2.contains(stmt3)); assertFalse(replicaGraph1.contains(stmt3)); assertFalse(replicaGraph3.contains(stmt3)); anzoClient2.commit(); anzoClient2.updateRepository(); TestUtilities.waitForStatement(replicaGraph1, stmt1, true); assertTrue(replicaGraph1.contains(stmt1)); TestUtilities.waitForStatement(replicaGraph2, stmt1, true); assertTrue(replicaGraph2.contains(stmt1)); TestUtilities.waitForStatement(replicaGraph3, stmt1, true); assertTrue(replicaGraph3.contains(stmt1)); TestUtilities.waitForStatement(replicaGraph1, stmt2, true); assertTrue(replicaGraph1.contains(stmt2)); TestUtilities.waitForStatement(replicaGraph2, stmt2, true); assertTrue(replicaGraph2.contains(stmt2)); TestUtilities.waitForStatement(replicaGraph3, stmt2, true); assertTrue(replicaGraph3.contains(stmt2)); TestUtilities.waitForStatement(replicaGraph1, stmt3, true); assertTrue(replicaGraph1.contains(stmt3)); TestUtilities.waitForStatement(replicaGraph2, stmt3, true); assertTrue(replicaGraph2.contains(stmt3)); TestUtilities.waitForStatement(replicaGraph3, stmt3, true); assertTrue(replicaGraph3.contains(stmt3)); // make sure all statement listeners received an update assertTrue(numAdded1 >= 3); assertTrue(numAdded2 >= 3); assertTrue(numAdded3 >= 3); numAdded1 = numAdded2 = numAdded3 = numRemoved1 = numRemoved2 = numRemoved3 = 0; assertTrue(!anzoClient1.getNamedGraphs().isEmpty()); assertTrue(anzoClient1.getNamedGraphs().contains(GRAPH_URI)); assertTrue(!anzoClient2.getNamedGraphs().isEmpty()); assertTrue(anzoClient2.getNamedGraphs().contains(GRAPH_URI)); assertTrue(!anzoClient3.getNamedGraphs().isEmpty()); assertTrue(anzoClient3.getNamedGraphs().contains(GRAPH_URI)); assertTrue(anzoClient1.getAllReplicaGraphsDataset().containsNamedGraph(GRAPH_URI)); assertTrue(anzoClient2.getAllReplicaGraphsDataset().containsNamedGraph(GRAPH_URI)); assertTrue(anzoClient3.getAllReplicaGraphsDataset().containsNamedGraph(GRAPH_URI)); // ---------------------------------------------------------------------- // close datasets anzoClient1.close(); anzoClient2.close(); anzoClient3.close(); // ----------------------------------------------------------------------- // make sure all replica graphs have been closed // closing the client should not close the graphs. // assertTrue(replicaGraph1.isClosed()); // assertTrue(replicaGraph1.isClosed()); // assertTrue(replicaGraph1.isClosed()); // ----------------------------------------------------------------------- // make sure local dataset is empty assertTrue(anzoClient3.getAllReplicaGraphsDataset().getNamedGraphUris().isEmpty()); } finally { if (anzoClient1 != null) { anzoClient1.close(); } if (anzoClient2 != null) { anzoClient2.close(); } if (anzoClient3 != null) { anzoClient3.close(); } } } private static class NotificationHelperThread implements Runnable { int notificationCount; final List<Throwable> exceptions; String containerName; Statement stmt; AnzoClient anzoClient = null; ClientGraph replicaGraph; public NotificationHelperThread(String containerName, Statement stmtToAdd) { this.containerName = containerName; this.stmt = stmtToAdd; exceptions = new ArrayList<Throwable>(); notificationCount = 0; initialize(); } private void initialize() { try { anzoClient = new AnzoClient(TestUpdates.getDefaultClientConfiguration()); anzoClient.connect(); replicaGraph = anzoClient.getReplicaGraph(GRAPH_URI); anzoClient.updateRepository(); assertNotNull(replicaGraph); replicaGraph.registerListener(new IStatementListener<INamedGraph>() { public void statementsRemoved(INamedGraph source, Statement... s) { } public void statementsAdded(INamedGraph source, Statement... s) { for (Statement stmt : s) { assertNotNull(stmt); notificationCount++; } } }); } catch (Throwable e) { synchronized (exceptions) { exceptions.add(e); } } } public void run() { try { replicaGraph.add(stmt); anzoClient.updateRepository(); Condition condition = new Condition() { @Override public boolean check() { return notificationCount >= 3; } }; TestUtilities.waitFor(condition); // long start = System.currentTimeMillis(); // while (true) { // long duration = System.currentTimeMillis() - start; // if (duration > (1000 * 10)) { // throw new Exception(Thread.currentThread().getName() + " Timed out waiting for notification additions."); // } // if (notificationCount >= 3) // break; // Thread.sleep(100); // } } catch (Throwable e) { System.err.println("had an exception!"); e.printStackTrace(); synchronized (exceptions) { exceptions.add(e); } } } } /** * Test adding statements to three graphs with the same URIs backed by three different dataset services run in three different threads. * * @throws Exception */ public void a_testNotificationsWithThreeClientsAndImmediateReplicationMultiThreaded() throws Exception { numAdded1 = numAdded2 = numAdded3 = numRemoved1 = numRemoved2 = numRemoved3 = 0; AnzoClient anzoClient = null; try { anzoClient = new AnzoClient(getDefaultClientConfiguration()); anzoClient.connect(); anzoClient.reset(loadStatements("initialize.trig"), null); } finally { if (anzoClient != null) anzoClient.close(); } final List<Throwable> exceptions = new LinkedList<Throwable>(); NotificationHelperThread helper1 = new NotificationHelperThread("dataService1", stmt1); NotificationHelperThread helper2 = new NotificationHelperThread("dataService2", stmt2); NotificationHelperThread helper3 = new NotificationHelperThread("dataService3", stmt3); try { Thread thread1 = new Thread(helper1, helper1.containerName); Thread thread2 = new Thread(helper2, helper2.containerName); Thread thread3 = new Thread(helper3, helper3.containerName); thread1.setPriority(Thread.MAX_PRIORITY); thread2.setPriority(Thread.MAX_PRIORITY); thread3.setPriority(Thread.MAX_PRIORITY); Thread.currentThread().setPriority(Thread.MIN_PRIORITY); thread1.start(); thread2.start(); thread3.start(); thread1.join(); thread2.join(); thread3.join(); if (!(exceptions.size() == 0)) throw new Exception(exceptions.get(0)); assertTrue(helper1.replicaGraph.contains(stmt1)); assertTrue(helper1.replicaGraph.contains(stmt2)); assertTrue(helper1.replicaGraph.contains(stmt3)); assertTrue(helper2.replicaGraph.contains(stmt1)); assertTrue(helper2.replicaGraph.contains(stmt2)); assertTrue(helper2.replicaGraph.contains(stmt3)); assertTrue(helper3.replicaGraph.contains(stmt1)); assertTrue(helper3.replicaGraph.contains(stmt2)); assertTrue(helper3.replicaGraph.contains(stmt3)); } finally { try { helper1.anzoClient.close(); } catch (Throwable t) { exceptions.add(t); } try { helper2.anzoClient.close(); } catch (Throwable t) { exceptions.add(t); } try { helper3.anzoClient.close(); } catch (Throwable t) { exceptions.add(t); } } if (!(exceptions.size() == 0)) throw new Exception(exceptions.get(0)); } int numNotificationConnStateChanged = 0, numNotificationExceptions = 0; /** * Test notifications * * @throws Exception */ public void testNotifications() throws Exception { final Statement stmt1 = Constants.valueFactory.createStatement(createTestUri("subject1"), createTestUri("predicate1"), createTestUri("object1")); AnzoClient anzoClient1 = null; try { // // create DATASET SERVICE 1 (CLIENT 1) // anzoClient1 = new AnzoClient(getDefaultClientConfiguration()); anzoClient1.connect(); anzoClient1.reset(loadStatements("initialize.trig"), null); ClientGraph replicaGraph1 = anzoClient1.getReplicaGraph(GRAPH_URI); assertNotNull(replicaGraph1); numAdded1 = numRemoved1 = 0; replicaGraph1.registerListener(new IStatementListener<INamedGraph>() { public void statementsRemoved(INamedGraph source, Statement... stmts) { for (Statement s : stmts) { if (s.getNamedGraphUri().equals(GRAPH_URI)) numRemoved1++; } } public void statementsAdded(INamedGraph source, Statement... stmts) { for (Statement s : stmts) { if (s.getNamedGraphUri().equals(GRAPH_URI)) numAdded1++; } } }); replicaGraph1.add(stmt1); assertEquals(0, numAdded1); anzoClient1.updateRepository(); assertEquals(1, numAdded1); } finally { if (anzoClient1 != null) anzoClient1.close(); } } /** * A utility method that extracts the revision number from the given metadata graph and returns it. * * @param graph1 * @return */ private long getNamedGraphRevision(IAnzoGraph graph) { Long revision = null; if (graph.getMetadataGraph().contains(graph.getNamedGraphUri(), NamedGraph.revisionProperty, null)) { Iterator<Statement> ei = graph.getMetadataGraph().find(graph.getNamedGraphUri(), NamedGraph.revisionProperty, null).iterator(); if (ei.hasNext()) { revision = (Long) StatementUtils.getNativeValue(((Literal) ei.next().getObject())); } } return revision; } }