Java tutorial
/** * 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.marmotta.kiwi.reasoner.test.persistence; import static org.hamcrest.Matchers.allOf; import static org.hamcrest.Matchers.hasItem; import static org.hamcrest.Matchers.hasItems; import static org.hamcrest.Matchers.not; import info.aduna.iteration.CloseableIteration; import java.sql.BatchUpdateException; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import org.apache.commons.lang3.RandomStringUtils; import org.apache.marmotta.kiwi.config.KiWiConfiguration; import org.apache.marmotta.kiwi.model.rdf.KiWiTriple; import org.apache.marmotta.kiwi.persistence.KiWiPersistence; import org.apache.marmotta.kiwi.reasoner.model.program.Justification; import org.apache.marmotta.kiwi.reasoner.model.program.Program; import org.apache.marmotta.kiwi.reasoner.parser.KWRLProgramParser; import org.apache.marmotta.kiwi.reasoner.parser.KWRLProgramParserBase; import org.apache.marmotta.kiwi.reasoner.persistence.KiWiReasoningConnection; import org.apache.marmotta.kiwi.reasoner.persistence.KiWiReasoningPersistence; import org.apache.marmotta.kiwi.sail.KiWiStore; import org.apache.marmotta.kiwi.sail.KiWiValueFactory; import org.apache.marmotta.kiwi.test.junit.KiWiDatabaseRunner; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TestWatcher; import org.junit.runner.Description; import org.junit.runner.RunWith; import org.openrdf.model.Statement; import org.openrdf.model.URI; import org.openrdf.repository.Repository; import org.openrdf.repository.RepositoryConnection; import org.openrdf.repository.sail.SailRepository; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * This test verifies the persistence functionality of the reasoning component regarding storing, loading and deleting * reasoning programs. * * @see org.apache.marmotta.kiwi.persistence.KiWiConnection * @see org.apache.marmotta.kiwi.persistence.KiWiPersistence * @author Sebastian Schaffert (sschaffert@apache.org) */ @RunWith(KiWiDatabaseRunner.class) public class JustificationPersistenceTest { private KiWiPersistence persistence; private KiWiReasoningPersistence rpersistence; private Repository repository; private final KiWiConfiguration config; public JustificationPersistenceTest(KiWiConfiguration config) { this.config = config; } @Before public void initDatabase() throws Exception { KiWiStore store = new KiWiStore(config); repository = new SailRepository(store); repository.initialize(); persistence = store.getPersistence(); rpersistence = new KiWiReasoningPersistence(persistence, repository.getValueFactory()); rpersistence.initDatabase(); } @After public void dropDatabase() throws Exception { rpersistence.dropDatabase(); persistence.dropDatabase(); repository.shutDown(); } final Logger logger = LoggerFactory.getLogger(JustificationPersistenceTest.class); /** * Test 1: create some triples through a repository connection (some inferred, some base), load a program, and * store justifications for the inferred triples based on rules and base triples. Test the different listing * functions. * */ @Test public void testStoreJustifications() throws Exception { KiWiValueFactory v = (KiWiValueFactory) repository.getValueFactory(); URI ctxb = v.createURI("http://localhost/context/default"); URI ctxi = v.createURI("http://localhost/context/inferred"); URI s1 = v.createURI("http://localhost/resource/" + RandomStringUtils.randomAlphanumeric(8)); URI s2 = v.createURI("http://localhost/resource/" + RandomStringUtils.randomAlphanumeric(8)); URI s3 = v.createURI("http://localhost/resource/" + RandomStringUtils.randomAlphanumeric(8)); URI p1 = v.createURI("http://localhost/resource/" + RandomStringUtils.randomAlphanumeric(8)); URI p2 = v.createURI("http://localhost/resource/" + RandomStringUtils.randomAlphanumeric(8)); URI o1 = v.createURI("http://localhost/resource/" + RandomStringUtils.randomAlphanumeric(8)); URI o2 = v.createURI("http://localhost/resource/" + RandomStringUtils.randomAlphanumeric(8)); URI o3 = v.createURI("http://localhost/resource/" + RandomStringUtils.randomAlphanumeric(8)); // first, load a sample program (it does not really matter what it actually contains, since we are not really // running the reasoner) KWRLProgramParserBase parser = new KWRLProgramParser(v, this.getClass().getResourceAsStream("test-001.kwrl")); Program p = parser.parseProgram(); p.setName("test-001"); KiWiReasoningConnection connection = rpersistence.getConnection(); try { // should not throw an exception and the program should have a database ID afterwards connection.storeProgram(p); connection.commit(); } finally { connection.close(); } // then get a connection to the repository and create a number of triples, some inferred and some base RepositoryConnection con = repository.getConnection(); try { con.add(s1, p1, o1); con.add(s2, p1, o2); con.add(s3, p1, o3); con.add(s1, p2, o1, ctxi); con.add(s2, p2, o2, ctxi); con.add(s3, p2, o3, ctxi); con.commit(); } finally { con.close(); } connection = rpersistence.getConnection(); try { // retrieve the persisted triples and put them into two sets to build justifications List<Statement> baseTriples = asList( connection.listTriples(null, null, null, v.convert(ctxb), false, true)); List<Statement> infTriples = asList( connection.listTriples(null, null, null, v.convert(ctxi), true, true)); Assert.assertEquals("number of base triples was not 3", 3, baseTriples.size()); Assert.assertEquals("number of inferred triples was not 3", 3, infTriples.size()); // we manually update the "inferred" flag for all inferred triples, since this is not possible through the // repository API PreparedStatement updateInferred = connection.getJDBCConnection() .prepareStatement("UPDATE triples SET inferred = true WHERE id = ?"); for (Statement stmt : infTriples) { KiWiTriple triple = (KiWiTriple) stmt; updateInferred.setLong(1, triple.getId()); updateInferred.addBatch(); } updateInferred.executeBatch(); updateInferred.close(); // now we create some justifications for the inferred triples and store them Set<Justification> justifications = new HashSet<Justification>(); Justification j1 = new Justification(); j1.getSupportingRules().add(p.getRules().get(0)); j1.getSupportingRules().add(p.getRules().get(1)); j1.getSupportingTriples().add((KiWiTriple) baseTriples.get(0)); j1.getSupportingTriples().add((KiWiTriple) baseTriples.get(1)); j1.setTriple((KiWiTriple) infTriples.get(0)); justifications.add(j1); Justification j2 = new Justification(); j2.getSupportingRules().add(p.getRules().get(1)); j2.getSupportingTriples().add((KiWiTriple) baseTriples.get(1)); j2.getSupportingTriples().add((KiWiTriple) baseTriples.get(2)); j2.setTriple((KiWiTriple) infTriples.get(1)); justifications.add(j2); connection.storeJustifications(justifications); connection.commit(); // we should now have two justifications in the database PreparedStatement listJustifications = connection.getJDBCConnection() .prepareStatement("SELECT count(*) AS count FROM reasoner_justifications"); ResultSet resultListJustifications = listJustifications.executeQuery(); Assert.assertTrue(resultListJustifications.next()); Assert.assertEquals(2, resultListJustifications.getInt("count")); resultListJustifications.close(); connection.commit(); PreparedStatement listSupportingTriples = connection.getJDBCConnection() .prepareStatement("SELECT count(*) AS count FROM reasoner_just_supp_triples"); ResultSet resultListSupportingTriples = listSupportingTriples.executeQuery(); Assert.assertTrue(resultListSupportingTriples.next()); Assert.assertEquals(4, resultListSupportingTriples.getInt("count")); resultListSupportingTriples.close(); connection.commit(); PreparedStatement listSupportingRules = connection.getJDBCConnection() .prepareStatement("SELECT count(*) AS count FROM reasoner_just_supp_rules"); ResultSet resultListSupportingRules = listSupportingRules.executeQuery(); Assert.assertTrue(resultListSupportingRules.next()); Assert.assertEquals(3, resultListSupportingRules.getInt("count")); resultListSupportingRules.close(); connection.commit(); // *** check listing justifications by base triple (supporting triple) // there should now be two justifications based on triple baseTriples.get(1)) List<Justification> supported1 = asList( connection.listJustificationsBySupporting((KiWiTriple) baseTriples.get(1))); Assert.assertEquals("number of justifications is wrong", 2, supported1.size()); Assert.assertThat("justifications differ", supported1, hasItems(j1, j2)); // only j1 should be supported by triple baseTriples.get(0)) List<Justification> supported2 = asList( connection.listJustificationsBySupporting((KiWiTriple) baseTriples.get(0))); Assert.assertEquals("number of justifications is wrong", 1, supported2.size()); Assert.assertThat("justifications differ", supported2, allOf(hasItem(j1), not(hasItem(j2)))); // only j2 should be supported by triple baseTriples.get(2)) List<Justification> supported3 = asList( connection.listJustificationsBySupporting((KiWiTriple) baseTriples.get(2))); Assert.assertEquals("number of justifications is wrong", 1, supported3.size()); Assert.assertThat("justifications differ", supported3, allOf(hasItem(j2), not(hasItem(j1)))); // *** check listing justificatoins by supporting rule // there should now be two justifications based on triple p.getRules().get(1) List<Justification> supported4 = asList(connection.listJustificationsBySupporting(p.getRules().get(1))); Assert.assertEquals("number of justifications is wrong", 2, supported4.size()); Assert.assertThat("justifications differ", supported4, hasItems(j1, j2)); // only j1 should be supported by triple p.getRules().get(0) List<Justification> supported5 = asList(connection.listJustificationsBySupporting(p.getRules().get(0))); Assert.assertEquals("number of justifications is wrong", 1, supported5.size()); Assert.assertThat("justifications differ", supported5, allOf(hasItem(j1), not(hasItem(j2)))); // *** check listing justifications by supported (inferred) triple // there should now be one justification supporting infTriples.get(0) List<Justification> supported6 = asList( connection.listJustificationsForTriple((KiWiTriple) infTriples.get(0))); Assert.assertEquals("number of justifications is wrong", 1, supported6.size()); Assert.assertThat("justifications differ", supported6, allOf(hasItem(j1), not(hasItem(j2)))); // there should now be one justification supporting infTriples.get(1) List<Justification> supported7 = asList( connection.listJustificationsForTriple((KiWiTriple) infTriples.get(1))); Assert.assertEquals("number of justifications is wrong", 1, supported7.size()); Assert.assertThat("justifications differ", supported7, allOf(hasItem(j2), not(hasItem(j1)))); // there should now be no justification supporting infTriples.get(2) List<Justification> supported8 = asList( connection.listJustificationsForTriple((KiWiTriple) infTriples.get(2))); Assert.assertEquals("number of justifications is wrong", 0, supported8.size()); // *** check listing unsupported triples List<KiWiTriple> unsupported = asList(connection.listUnsupportedTriples()); Assert.assertEquals("number of unsupported triples is wrong", 1, unsupported.size()); Assert.assertThat("unsupported triples differ", unsupported, hasItem((KiWiTriple) infTriples.get(2))); // now we delete justification 2; as a consequence, // - there should be only once justification left // - there should be two unsupported triples connection.deleteJustifications(Collections.singleton(j2)); // we should now have one justifications in the database resultListJustifications = listJustifications.executeQuery(); Assert.assertTrue(resultListJustifications.next()); Assert.assertEquals(1, resultListJustifications.getInt("count")); resultListJustifications.close(); connection.commit(); resultListSupportingTriples = listSupportingTriples.executeQuery(); Assert.assertTrue(resultListSupportingTriples.next()); Assert.assertEquals(2, resultListSupportingTriples.getInt("count")); resultListSupportingTriples.close(); connection.commit(); resultListSupportingRules = listSupportingRules.executeQuery(); Assert.assertTrue(resultListSupportingRules.next()); Assert.assertEquals(2, resultListSupportingRules.getInt("count")); resultListSupportingRules.close(); connection.commit(); List<KiWiTriple> unsupported2 = asList(connection.listUnsupportedTriples()); Assert.assertEquals("number of unsupported triples is wrong", 2, unsupported2.size()); Assert.assertThat("unsupported triples differ", unsupported2, hasItem((KiWiTriple) infTriples.get(1))); } catch (BatchUpdateException ex) { if (ex.getNextException() != null) { ex.printStackTrace(); throw ex.getNextException(); } else { throw ex; } } finally { connection.close(); } } /** * Workaround for https://openrdf.atlassian.net/browse/SES-1702 in Sesame 2.7.0-beta1 * @param <E> * @return */ public static <E, X extends Exception> List<E> asList(CloseableIteration<E, X> result) throws Exception { ArrayList<E> collection = new ArrayList<E>(); try { while (result.hasNext()) { collection.add(result.next()); } return collection; } finally { result.close(); } } }