/* * 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.stanbol.enhancer.engines.dereference; import static org.apache.stanbol.enhancer.engines.dereference.DereferenceConstants.ENTITY_REFERENCES; import static org.apache.stanbol.enhancer.engines.dereference.DereferenceConstants.FILTER_ACCEPT_LANGUAGES; import static org.apache.stanbol.enhancer.engines.dereference.DereferenceConstants.FILTER_CONTENT_LANGUAGES; import static org.apache.stanbol.enhancer.servicesapi.rdf.OntologicalClasses.SKOS_CONCEPT; import static org.apache.stanbol.enhancer.servicesapi.rdf.Properties.ENHANCER_ENTITY_REFERENCE; import static org.apache.stanbol.enhancer.servicesapi.rdf.Properties.RDFS_LABEL; import static org.apache.stanbol.enhancer.servicesapi.rdf.Properties.RDF_TYPE; import java.io.IOException; import java.util.Collections; import java.util.Dictionary; import java.util.Hashtable; import java.util.Iterator; import java.util.Random; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.locks.Lock; import org.apache.clerezza.commons.rdf.Language; import org.apache.clerezza.rdf.core.LiteralFactory; import org.apache.clerezza.commons.rdf.Graph; import org.apache.clerezza.commons.rdf.Triple; import org.apache.clerezza.commons.rdf.Graph; import org.apache.clerezza.commons.rdf.IRI; import org.apache.clerezza.commons.rdf.impl.utils.PlainLiteralImpl; import org.apache.clerezza.commons.rdf.impl.utils.TripleImpl; import org.apache.stanbol.commons.indexedgraph.IndexedGraph; import org.apache.stanbol.commons.stanboltools.offline.OfflineMode; import org.apache.stanbol.enhancer.contentitem.inmemory.InMemoryContentItemFactory; import org.apache.stanbol.enhancer.servicesapi.ContentItem; import org.apache.stanbol.enhancer.servicesapi.ContentItemFactory; import org.apache.stanbol.enhancer.servicesapi.EnhancementEngine; import org.apache.stanbol.enhancer.servicesapi.impl.StringSource; import org.apache.stanbol.enhancer.servicesapi.rdf.NamespaceEnum; import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * TODO: convert this to an integration test! * @author Rupert Westenthaler */ public class DereferenceEngineTest { private final static Logger log = LoggerFactory.getLogger(DereferenceEngineTest.class); //TODO: test implementations of EntityDereferencer static EntityDereferencer asyncDereferencer = new TestDereferencer(Executors.newFixedThreadPool(4)); static EntityDereferencer syncDereferencer = new TestDereferencer(null); /** * The metadata used by this test */ private static Graph testData; private static Graph testMetadata; public static final IRI NAME = new IRI(NamespaceEnum.rdfs+"label"); public static final IRI TYPE = new IRI(NamespaceEnum.rdf+"type"); public static final IRI REDIRECT = new IRI(NamespaceEnum.rdfs+"seeAlso"); public static final IRI OTHER_ENTITY_REFERENCE = new IRI( "http://www.example.org/stanbol/enhancer/dereference/test#other-entity-reference"); private static final ContentItemFactory ciFactory = InMemoryContentItemFactory.getInstance(); private static final LiteralFactory lf = LiteralFactory.getInstance(); private static final IRI SKOS_NOTATION = new IRI(NamespaceEnum.skos+"notation"); private static final Language LANG_EN = new Language("en"); private static final Language LANG_DE = new Language("de"); private static final int NUM_ENTITIES = 1000; public static final float PERCENTAGE_LINKED = 0.3f; public static final float PERCENTAGE_LINKED_OTHER = 0.2f; public static final float PERCENTAGE_PRESENT = 0.9f; @BeforeClass public static void setUpServices() throws IOException { testData = new IndexedGraph(); long seed = System.currentTimeMillis(); log.info("Test seed "+ seed); Random random = new Random(seed); int numEntities = 0; for(int i = 0; i < NUM_ENTITIES ; i++){ if(random.nextFloat() <= PERCENTAGE_PRESENT){ //do not create all entities IRI uri = new IRI("urn:test:entity"+i); testData.add(new TripleImpl(uri, RDF_TYPE, SKOS_CONCEPT)); testData.add(new TripleImpl(uri, RDFS_LABEL, new PlainLiteralImpl("entity "+i, LANG_EN))); testData.add(new TripleImpl(uri, RDFS_LABEL, new PlainLiteralImpl("Entity "+i, LANG_DE))); testData.add(new TripleImpl(uri, SKOS_NOTATION, lf.createTypedLiteral(i))); numEntities++; } } log.info(" ... created {} Entities",numEntities); testMetadata = new IndexedGraph(); int numLinks = 0; int numOtherLinks = 0; for(int i = 0; i < NUM_ENTITIES ; i++){ float r = random.nextFloat(); if(r < PERCENTAGE_LINKED){ IRI enhancementUri = new IRI("urn:test:enhancement"+i); IRI entityUri = new IRI("urn:test:entity"+i); //we do not need any other triple for testing in the contentItem testMetadata.add(new TripleImpl(enhancementUri, ENHANCER_ENTITY_REFERENCE, entityUri)); numLinks++; } else if((r-PERCENTAGE_LINKED) < PERCENTAGE_LINKED_OTHER){ IRI enhancementUri = new IRI("urn:test:enhancement"+i); IRI entityUri = new IRI("urn:test:entity"+i); //we do not need any other triple for testing in the contentItem testMetadata.add(new TripleImpl(enhancementUri, OTHER_ENTITY_REFERENCE, entityUri)); numOtherLinks++; } } log.info("> created {} Entity references and {} references using an alternative proeprty ", numLinks, numOtherLinks); } public static ContentItem getContentItem(final String id) throws IOException { ContentItem ci = ciFactory.createContentItem(new IRI(id), new StringSource("Not used")); ci.getMetadata().addAll(testMetadata); return ci; } /** * Test {@link OfflineMode} functionality * @throws Exception */ @Test public void testOfflineMode() throws Exception { ContentItem ci = getContentItem("urn:test:testOfflineMode"); EntityDereferencer onlineDereferencer = new TestDereferencer(null){ @Override public boolean supportsOfflineMode() { return false; } }; Dictionary<String,Object> dict = new Hashtable<String,Object>(); dict.put(EnhancementEngine.PROPERTY_NAME, "online"); dict.put(FILTER_CONTENT_LANGUAGES, false); dict.put(FILTER_ACCEPT_LANGUAGES, false); EntityDereferenceEngine engine = new EntityDereferenceEngine(onlineDereferencer, new DereferenceEngineConfig(dict, null)); //engine in online mode Assert.assertNotEquals(engine.canEnhance(ci), EnhancementEngine.CANNOT_ENHANCE); //set engine in offline mode engine.setOfflineMode(true); Assert.assertEquals(engine.canEnhance(ci), EnhancementEngine.CANNOT_ENHANCE); } @Test public void testSyncDereferencing() throws Exception { ContentItem ci = getContentItem("urn:test:testSyncDereferencing"); Dictionary<String,Object> dict = new Hashtable<String,Object>(); dict.put(EnhancementEngine.PROPERTY_NAME, "sync"); dict.put(FILTER_CONTENT_LANGUAGES, false); dict.put(FILTER_ACCEPT_LANGUAGES, false); EntityDereferenceEngine engine = new EntityDereferenceEngine(syncDereferencer, new DereferenceEngineConfig(dict, null)); Assert.assertNotEquals(engine.canEnhance(ci), EnhancementEngine.CANNOT_ENHANCE); engine.computeEnhancements(ci); validateDereferencedEntities(ci.getMetadata(), ENHANCER_ENTITY_REFERENCE); } @Test public void testAsyncDereferencing() throws Exception { ContentItem ci = getContentItem("urn:test:testSyncDereferencing"); Dictionary<String,Object> dict = new Hashtable<String,Object>(); dict.put(EnhancementEngine.PROPERTY_NAME, "async"); dict.put(FILTER_CONTENT_LANGUAGES, false); dict.put(FILTER_ACCEPT_LANGUAGES, false); EntityDereferenceEngine engine = new EntityDereferenceEngine(asyncDereferencer, new DereferenceEngineConfig(dict,null)); Assert.assertNotEquals(engine.canEnhance(ci), EnhancementEngine.CANNOT_ENHANCE); engine.computeEnhancements(ci); validateDereferencedEntities(ci.getMetadata(), ENHANCER_ENTITY_REFERENCE); } /** * Test for <a href="https://issues.apache.org/jira/browse/STANBOL-1334">STANBOL-1334</a> * @throws Exception */ @Test public void testAsyncOtherEntityReferenceDereferencing() throws Exception { ContentItem ci = getContentItem("urn:test:testSyncDereferencing"); Dictionary<String,Object> dict = new Hashtable<String,Object>(); dict.put(EnhancementEngine.PROPERTY_NAME, "async"); dict.put(FILTER_CONTENT_LANGUAGES, false); dict.put(FILTER_ACCEPT_LANGUAGES, false); dict.put(ENTITY_REFERENCES,OTHER_ENTITY_REFERENCE.getUnicodeString()); DereferenceEngineConfig config = new DereferenceEngineConfig(dict,null); EntityDereferenceEngine engine = new EntityDereferenceEngine(asyncDereferencer, config); Assert.assertNotEquals(engine.canEnhance(ci), EnhancementEngine.CANNOT_ENHANCE); engine.computeEnhancements(ci); validateDereferencedEntities(ci.getMetadata(), OTHER_ENTITY_REFERENCE); } /** * Test for <a href="https://issues.apache.org/jira/browse/STANBOL-1334">STANBOL-1334</a> * @throws Exception */ @Test public void testAsyncMultipleEntityReferenceDereferencing() throws Exception { ContentItem ci = getContentItem("urn:test:testSyncDereferencing"); Dictionary<String,Object> dict = new Hashtable<String,Object>(); dict.put(EnhancementEngine.PROPERTY_NAME, "async"); dict.put(FILTER_CONTENT_LANGUAGES, false); dict.put(FILTER_ACCEPT_LANGUAGES, false); dict.put(ENTITY_REFERENCES, new String[]{ OTHER_ENTITY_REFERENCE.getUnicodeString(), ENHANCER_ENTITY_REFERENCE.getUnicodeString()}); DereferenceEngineConfig config = new DereferenceEngineConfig(dict,null); EntityDereferenceEngine engine = new EntityDereferenceEngine(asyncDereferencer, config); Assert.assertNotEquals(engine.canEnhance(ci), EnhancementEngine.CANNOT_ENHANCE); engine.computeEnhancements(ci); validateDereferencedEntities(ci.getMetadata(), OTHER_ENTITY_REFERENCE, ENHANCER_ENTITY_REFERENCE); } private void validateDereferencedEntities(Graph metadata, IRI...entityReferenceFields) { Graph expected = new IndexedGraph(); for(IRI entityReferenceField : entityReferenceFields){ Iterator<Triple> referenced = metadata.filter(null, entityReferenceField, null); while(referenced.hasNext()){ IRI entity = (IRI)referenced.next().getObject(); Iterator<Triple> entityTriples = testData.filter(entity, null, null); while(entityTriples.hasNext()){ expected.add(entityTriples.next()); } } } Graph notExpected = new IndexedGraph(testData); notExpected.removeAll(expected); Assert.assertTrue(metadata.containsAll(expected)); Assert.assertTrue(Collections.disjoint(metadata, notExpected)); } private static class TestDereferencer implements EntityDereferencer { private final ExecutorService executorService; public TestDereferencer(ExecutorService executorService) { this.executorService = executorService; } @Override public boolean supportsOfflineMode() { return true; } @Override public ExecutorService getExecutor() { return executorService; } @Override public boolean dereference(IRI entity, Graph graph, Lock writeLock, DereferenceContext context) throws DereferenceException { Iterator<Triple> entityTriples = testData.filter(entity, null, null); if(entityTriples.hasNext()){ writeLock.lock(); try { do { graph.add(entityTriples.next()); } while (entityTriples.hasNext()); } finally { writeLock.unlock(); } return true; } else { return false; } } } }