diff --git a/README.md b/README.md index 0233966..dcdb0cf 100644 --- a/README.md +++ b/README.md @@ -1 +1 @@ -# eENVplus Thesaurus Framework Exploitation Service +# eENVplus Thesaurus Framework Exploitation Service \ No newline at end of file diff --git a/TF_Exploitation_Server_core/pom.xml b/TF_Exploitation_Server_core/pom.xml index 7190dbf..c73a1ba 100644 --- a/TF_Exploitation_Server_core/pom.xml +++ b/TF_Exploitation_Server_core/pom.xml @@ -7,7 +7,7 @@ net.disy.eenvplus eenvplus-tf-exploitation-server-parent - 0.3.3-SNAPSHOT + 0.4.4-SNAPSHOT diff --git a/TF_Exploitation_Server_core/src/main/java/net/disy/eenvplus/tfes/core/api/exceptions/UnknownRelationException.java b/TF_Exploitation_Server_core/src/main/java/net/disy/eenvplus/tfes/core/api/exceptions/UnknownRelationException.java new file mode 100644 index 0000000..c43ded7 --- /dev/null +++ b/TF_Exploitation_Server_core/src/main/java/net/disy/eenvplus/tfes/core/api/exceptions/UnknownRelationException.java @@ -0,0 +1,20 @@ +//Copyright (c) 2015 by Disy Informationssysteme GmbH +package net.disy.eenvplus.tfes.core.api.exceptions; + +// NOT_PUBLISHED + +public class UnknownRelationException extends ServiceException { + private static final long serialVersionUID = 1L; + + private final String relation; + + public UnknownRelationException(String relation) { + super(null); + this.relation = relation; + } + + public String getRelation() { + return relation; + } + +} diff --git a/TF_Exploitation_Server_core/src/main/java/net/disy/eenvplus/tfes/core/api/modules/IRelativeNeighbourhoodProviderServiceModule.java b/TF_Exploitation_Server_core/src/main/java/net/disy/eenvplus/tfes/core/api/modules/IRelativeNeighbourhoodProviderServiceModule.java new file mode 100644 index 0000000..f54af33 --- /dev/null +++ b/TF_Exploitation_Server_core/src/main/java/net/disy/eenvplus/tfes/core/api/modules/IRelativeNeighbourhoodProviderServiceModule.java @@ -0,0 +1,15 @@ +//Copyright (c) 2015 by Disy Informationssysteme GmbH +package net.disy.eenvplus.tfes.core.api.modules; + +import java.util.concurrent.Callable; + +import net.disy.eenvplus.tfes.core.api.query.IConceptQuery; +import net.disy.eenvplus.tfes.core.api.response.IVisualizationNode; + +// NOT_PUBLISHED + +public interface IRelativeNeighbourhoodProviderServiceModule extends IServiceModule { + + Callable getNeighbourhood(IConceptQuery query); + +} diff --git a/TF_Exploitation_Server_core/src/main/java/net/disy/eenvplus/tfes/core/api/query/QueryParameterKeys.java b/TF_Exploitation_Server_core/src/main/java/net/disy/eenvplus/tfes/core/api/query/QueryParameterKeys.java new file mode 100644 index 0000000..dfd3f3c --- /dev/null +++ b/TF_Exploitation_Server_core/src/main/java/net/disy/eenvplus/tfes/core/api/query/QueryParameterKeys.java @@ -0,0 +1,18 @@ +//Copyright (c) 2015 by Disy Informationssysteme GmbH +package net.disy.eenvplus.tfes.core.api.query; + +// NOT_PUBLISHED + +public enum QueryParameterKeys { + QUERY_DEPTH("query_depth"), RELATIONS("relations"); //$NON-NLS-1$//$NON-NLS-2$ + + private String key; + + private QueryParameterKeys(String key) { + this.key = key; + } + + public String getKey() { + return key; + } +} diff --git a/TF_Exploitation_Server_core/src/main/java/net/disy/eenvplus/tfes/core/api/response/IVisualizationNode.java b/TF_Exploitation_Server_core/src/main/java/net/disy/eenvplus/tfes/core/api/response/IVisualizationNode.java new file mode 100644 index 0000000..4d85759 --- /dev/null +++ b/TF_Exploitation_Server_core/src/main/java/net/disy/eenvplus/tfes/core/api/response/IVisualizationNode.java @@ -0,0 +1,13 @@ +//Copyright (c) 2015 by Disy Informationssysteme GmbH +package net.disy.eenvplus.tfes.core.api.response; + +import java.util.Collection; + +// NOT_PUBLISHED + +public interface IVisualizationNode { + IRelatedConcept getElement(); + + Collection getChildren(); + +} diff --git a/TF_Exploitation_Server_core/src/main/java/net/disy/eenvplus/tfes/core/api/service/IServiceManager.java b/TF_Exploitation_Server_core/src/main/java/net/disy/eenvplus/tfes/core/api/service/IServiceManager.java index c547e16..a3f3205 100644 --- a/TF_Exploitation_Server_core/src/main/java/net/disy/eenvplus/tfes/core/api/service/IServiceManager.java +++ b/TF_Exploitation_Server_core/src/main/java/net/disy/eenvplus/tfes/core/api/service/IServiceManager.java @@ -6,6 +6,7 @@ import net.disy.eenvplus.tfes.core.api.capabilities.ServiceModuleDescription; import net.disy.eenvplus.tfes.core.api.exceptions.ServiceException; +import net.disy.eenvplus.tfes.core.api.query.IConceptQuery; import net.disy.eenvplus.tfes.core.api.query.IDescribeConceptQuery; import net.disy.eenvplus.tfes.core.api.query.IRelativeQuery; import net.disy.eenvplus.tfes.core.api.query.IResolveThesaurusQuery; @@ -18,6 +19,7 @@ import net.disy.eenvplus.tfes.core.api.response.ISuggestion; import net.disy.eenvplus.tfes.core.api.response.ISynonym; import net.disy.eenvplus.tfes.core.api.response.ITopMostConcept; +import net.disy.eenvplus.tfes.core.api.response.IVisualizationNode; // NOT_PUBLISHED public interface IServiceManager { @@ -34,6 +36,8 @@ public interface IServiceManager { List getTopMostConceptDescriptions(); + List getRelativeNeighbourhoodDescriptions(); + Collection getSuggestions(ISuggestionQuery query) throws ServiceException; IConceptDescription describeConcept(IDescribeConceptQuery capture) throws ServiceException; @@ -47,4 +51,6 @@ public interface IServiceManager { Collection getTopMostConcepts(ITopMostConceptQuery query) throws ServiceException; + IVisualizationNode getRelativeNeighbourhood(IConceptQuery query) throws ServiceException; + } diff --git a/TF_Exploitation_Server_core/src/main/java/net/disy/eenvplus/tfes/core/manager/ServiceManager.java b/TF_Exploitation_Server_core/src/main/java/net/disy/eenvplus/tfes/core/manager/ServiceManager.java index 99d75cf..2431983 100644 --- a/TF_Exploitation_Server_core/src/main/java/net/disy/eenvplus/tfes/core/manager/ServiceManager.java +++ b/TF_Exploitation_Server_core/src/main/java/net/disy/eenvplus/tfes/core/manager/ServiceManager.java @@ -6,6 +6,7 @@ import net.disy.eenvplus.tfes.core.api.capabilities.ServiceModuleDescription; import net.disy.eenvplus.tfes.core.api.exceptions.ServiceException; +import net.disy.eenvplus.tfes.core.api.query.IConceptQuery; import net.disy.eenvplus.tfes.core.api.query.IDescribeConceptQuery; import net.disy.eenvplus.tfes.core.api.query.IRelativeQuery; import net.disy.eenvplus.tfes.core.api.query.IResolveThesaurusQuery; @@ -18,8 +19,10 @@ import net.disy.eenvplus.tfes.core.api.response.ISuggestion; import net.disy.eenvplus.tfes.core.api.response.ISynonym; import net.disy.eenvplus.tfes.core.api.response.ITopMostConcept; +import net.disy.eenvplus.tfes.core.api.response.IVisualizationNode; import net.disy.eenvplus.tfes.core.api.service.IServiceManager; import net.disy.eenvplus.tfes.core.module.DescribeConceptModulesManager; +import net.disy.eenvplus.tfes.core.module.RelatedNeighbourhoodModulesManager; import net.disy.eenvplus.tfes.core.module.RelativeModulesManager; import net.disy.eenvplus.tfes.core.module.ResolveThesaurusModulesManager; import net.disy.eenvplus.tfes.core.module.SuggestionModulesManager; @@ -45,6 +48,9 @@ public class ServiceManager implements IServiceManager { @Autowired private RelativeModulesManager relativeModulesManager; + @Autowired + private RelatedNeighbourhoodModulesManager relatedNeighbourhoodModulesManager; + @Autowired private SynonymModulesManager synonymModulesManager; @@ -113,4 +119,14 @@ public Collection getTopMostConcepts(ITopMostConceptQuery query return topMostConceptModulesManager.getTopMostConcepts(query); } + @Override + public List getRelativeNeighbourhoodDescriptions() { + return relatedNeighbourhoodModulesManager.getServiceModuleDescription(); + } + + @Override + public IVisualizationNode getRelativeNeighbourhood(IConceptQuery query) throws ServiceException { + return relatedNeighbourhoodModulesManager.getRelativeNeighbourhood(query); + } + } diff --git a/TF_Exploitation_Server_core/src/main/java/net/disy/eenvplus/tfes/core/module/DescribeConceptModulesManager.java b/TF_Exploitation_Server_core/src/main/java/net/disy/eenvplus/tfes/core/module/DescribeConceptModulesManager.java index 618f078..e4ae47c 100644 --- a/TF_Exploitation_Server_core/src/main/java/net/disy/eenvplus/tfes/core/module/DescribeConceptModulesManager.java +++ b/TF_Exploitation_Server_core/src/main/java/net/disy/eenvplus/tfes/core/module/DescribeConceptModulesManager.java @@ -2,10 +2,10 @@ package net.disy.eenvplus.tfes.core.module; import static net.disy.eenvplus.tfes.core.api.response.EmptyConceptDescription.EMPTY_CONCEPT; +import static net.disy.eenvplus.tfes.core.util.CollectionUtilities.first; import java.util.ArrayList; import java.util.Collection; -import java.util.Iterator; import java.util.List; import java.util.Set; import java.util.concurrent.Callable; @@ -44,11 +44,7 @@ public IConceptDescription getConceptDescription(IDescribeConceptQuery query) throws ServiceException { Set> futures = submitQuery(query); Collection results = retrieveResults(futures); - Iterator result = results.iterator(); - if (result.hasNext()) { - return result.next(); - } - return EMPTY_CONCEPT; + return first(results, EMPTY_CONCEPT); } } diff --git a/TF_Exploitation_Server_core/src/main/java/net/disy/eenvplus/tfes/core/module/RelatedNeighbourhoodModulesManager.java b/TF_Exploitation_Server_core/src/main/java/net/disy/eenvplus/tfes/core/module/RelatedNeighbourhoodModulesManager.java new file mode 100644 index 0000000..1e4875b --- /dev/null +++ b/TF_Exploitation_Server_core/src/main/java/net/disy/eenvplus/tfes/core/module/RelatedNeighbourhoodModulesManager.java @@ -0,0 +1,48 @@ +//Copyright (c) 2015 by Disy Informationssysteme GmbH +package net.disy.eenvplus.tfes.core.module; + +import static net.disy.eenvplus.tfes.core.util.CollectionUtilities.first; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Set; +import java.util.concurrent.Callable; +import java.util.concurrent.Future; + +import net.disy.eenvplus.tfes.core.api.exceptions.ServiceException; +import net.disy.eenvplus.tfes.core.api.modules.IRelativeNeighbourhoodProviderServiceModule; +import net.disy.eenvplus.tfes.core.api.query.IConceptQuery; +import net.disy.eenvplus.tfes.core.api.response.IVisualizationNode; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +// NOT_PUBLISHED +@Service +public class RelatedNeighbourhoodModulesManager + extends + AbstractModuleManager { + + @Autowired(required = false) + List modules = new ArrayList<>(); + + @Override + protected List getServiceModules() { + return modules; + } + + @Override + protected Callable createCallable( + IConceptQuery query, + IRelativeNeighbourhoodProviderServiceModule module) { + return module.getNeighbourhood(query); + } + + public IVisualizationNode getRelativeNeighbourhood(IConceptQuery query) throws ServiceException { + Set> futures = submitQuery(query); + Collection results = retrieveResults(futures); + return first(results, null); + } + +} diff --git a/TF_Exploitation_Server_core/src/main/java/net/disy/eenvplus/tfes/core/util/CollectionUtilities.java b/TF_Exploitation_Server_core/src/main/java/net/disy/eenvplus/tfes/core/util/CollectionUtilities.java index a006710..94ccc34 100644 --- a/TF_Exploitation_Server_core/src/main/java/net/disy/eenvplus/tfes/core/util/CollectionUtilities.java +++ b/TF_Exploitation_Server_core/src/main/java/net/disy/eenvplus/tfes/core/util/CollectionUtilities.java @@ -2,6 +2,7 @@ package net.disy.eenvplus.tfes.core.util; import java.util.Collection; +import java.util.Iterator; import java.util.LinkedList; import java.util.List; @@ -30,4 +31,12 @@ public static List limitResults(List list, int maxIndex) { return list; } + public static E first(Collection collection, E alternative) { + Iterator iterator = collection.iterator(); + if (iterator.hasNext()) { + return iterator.next(); + } + return alternative; + } + } diff --git a/TF_Exploitation_Server_core/src/test/java/net/disy/eenvplus/tfes/core/api/query/IConceptQueryMatcher.java b/TF_Exploitation_Server_core/src/test/java/net/disy/eenvplus/tfes/core/api/query/IConceptQueryMatcher.java index a8d955c..279f0b1 100644 --- a/TF_Exploitation_Server_core/src/test/java/net/disy/eenvplus/tfes/core/api/query/IConceptQueryMatcher.java +++ b/TF_Exploitation_Server_core/src/test/java/net/disy/eenvplus/tfes/core/api/query/IConceptQueryMatcher.java @@ -7,7 +7,7 @@ // NOT_PUBLISHED public class IConceptQueryMatcher { - public static Matcher hasKeyword(Matcher expected) { + public static Matcher hasConcept(Matcher expected) { return new FeatureMatcher(expected, "Concept", "Concept") { //$NON-NLS-1$ //$NON-NLS-2$ @Override diff --git a/TF_Exploitation_Server_core/src/test/java/net/disy/eenvplus/tfes/core/api/query/IServiceQueryMatcher.java b/TF_Exploitation_Server_core/src/test/java/net/disy/eenvplus/tfes/core/api/query/IServiceQueryMatcher.java index 64b364c..12d856a 100644 --- a/TF_Exploitation_Server_core/src/test/java/net/disy/eenvplus/tfes/core/api/query/IServiceQueryMatcher.java +++ b/TF_Exploitation_Server_core/src/test/java/net/disy/eenvplus/tfes/core/api/query/IServiceQueryMatcher.java @@ -3,6 +3,7 @@ import static org.hamcrest.Matchers.allOf; import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.hasEntry; import static org.hamcrest.Matchers.is; import java.util.Map; @@ -66,20 +67,27 @@ protected Iterable featureValueOf(IServiceQuery query) { }; } - public static Matcher hasExtraParameters( - Matcher> expected) { - return new FeatureMatcher>( + public static Matcher hasExtraParameters( + Matcher> expected) { + return new FeatureMatcher>( expected, "Extra Parameters", "Extra Parameters") { //$NON-NLS-1$ //$NON-NLS-2$ + @SuppressWarnings("unchecked") @Override - protected Map featureValueOf(IServiceQuery query) { - return query.getExtraParameters(); + protected Map featureValueOf(IServiceQuery query) { + return (Map) query.getExtraParameters(); } }; } + public static Matcher hasExtraParameters( + QueryParameterKeys key, + Matcher expectedValue) { + return hasExtraParameters(hasEntry(is(key.getKey()), expectedValue)); + } + public static Matcher isEmptyQuery() { return allOf( hasLanguages(NO_ENTRIES), diff --git a/TF_Exploitation_Server_core/src/test/java/net/disy/eenvplus/tfes/core/api/response/IRelatedConceptBuilder.java b/TF_Exploitation_Server_core/src/test/java/net/disy/eenvplus/tfes/core/api/response/IRelatedConceptBuilder.java new file mode 100644 index 0000000..3738320 --- /dev/null +++ b/TF_Exploitation_Server_core/src/test/java/net/disy/eenvplus/tfes/core/api/response/IRelatedConceptBuilder.java @@ -0,0 +1,80 @@ +package net.disy.eenvplus.tfes.core.api.response; + +public class IRelatedConceptBuilder { + + private String conceptUri; + private String sourceLabel; + private String language; + private String label; + private String relationUri; + private String relationLabel; + + private IRelatedConceptBuilder(String conceptUri) { + this.conceptUri = conceptUri; + } + + public static IRelatedConceptBuilder forConceptUri(String conceptUri) { + return new IRelatedConceptBuilder(conceptUri); + } + + public IRelatedConceptBuilder withLabel(String label) { + this.label = label; + return this; + } + + public IRelatedConceptBuilder withLanguage(String language) { + this.language = language; + return this; + } + + public IRelatedConceptBuilder withRelationUri(String relationUri) { + this.relationUri = relationUri; + return this; + } + + public IRelatedConceptBuilder withRelationLabel(String relationLabel) { + this.relationLabel = relationLabel; + return this; + } + + public IRelatedConceptBuilder withSourceLabel(String sourceLabel) { + this.sourceLabel = sourceLabel; + return this; + } + + public IRelatedConcept build() { + return new IRelatedConcept() { + + @Override + public String getSourceLabel() { + return sourceLabel; + } + + @Override + public String getLanguage() { + return language; + } + + @Override + public String getLabel() { + return label; + } + + @Override + public String getConceptUri() { + return conceptUri; + } + + @Override + public String getRelationUri() { + return relationUri; + } + + @Override + public String getRelationLabel() { + return relationLabel; + } + }; + } + +} diff --git a/TF_Exploitation_Server_core/src/test/java/net/disy/eenvplus/tfes/core/api/response/IVisualizationNodeMatcher.java b/TF_Exploitation_Server_core/src/test/java/net/disy/eenvplus/tfes/core/api/response/IVisualizationNodeMatcher.java new file mode 100644 index 0000000..ad22a6c --- /dev/null +++ b/TF_Exploitation_Server_core/src/test/java/net/disy/eenvplus/tfes/core/api/response/IVisualizationNodeMatcher.java @@ -0,0 +1,35 @@ +package net.disy.eenvplus.tfes.core.api.response; + +import java.util.Collection; + +import org.hamcrest.FeatureMatcher; +import org.hamcrest.Matcher; + +public class IVisualizationNodeMatcher { + + public static Matcher hasElement(Matcher expected) { + return new FeatureMatcher(expected, "Element", "Element") { //$NON-NLS-1$ //$NON-NLS-2$ + + @Override + protected IRelatedConcept featureValueOf(IVisualizationNode node) { + return node.getElement(); + } + + }; + } + + public static Matcher hasChildren( + Matcher> expected) { + return new FeatureMatcher>( + expected, + "Children", "Children") { //$NON-NLS-1$ //$NON-NLS-2$ + + @Override + protected Collection featureValueOf(IVisualizationNode node) { + return node.getChildren(); + } + + }; + } + +} diff --git a/TF_Exploitation_Server_core/src/test/java/net/disy/eenvplus/tfes/core/module/RelatedNeighbourhoodModulesManagerTest.java b/TF_Exploitation_Server_core/src/test/java/net/disy/eenvplus/tfes/core/module/RelatedNeighbourhoodModulesManagerTest.java new file mode 100644 index 0000000..70585e1 --- /dev/null +++ b/TF_Exploitation_Server_core/src/test/java/net/disy/eenvplus/tfes/core/module/RelatedNeighbourhoodModulesManagerTest.java @@ -0,0 +1,53 @@ +package net.disy.eenvplus.tfes.core.module; + +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.util.concurrent.Callable; + +import net.disy.eenvplus.tfes.core.api.modules.IRelativeNeighbourhoodProviderServiceModule; +import net.disy.eenvplus.tfes.core.api.query.IConceptQuery; +import net.disy.eenvplus.tfes.core.api.response.IVisualizationNode; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; + +@RunWith(MockitoJUnitRunner.class) +public class RelatedNeighbourhoodModulesManagerTest { + + @Mock + private IConceptQuery query; + + @Mock + private IRelativeNeighbourhoodProviderServiceModule module; + + @InjectMocks + private RelatedNeighbourhoodModulesManager manager; + + @Before + public void setUp() { + manager.modules.add(module); + } + + private Callable createModuleResult(final IVisualizationNode result) { + return new Callable() { + @Override + public IVisualizationNode call() throws Exception { + return result; + } + }; + } + + @Test + public void delegatesQueryToModule() throws Exception { + when(module.getNeighbourhood(query)).thenReturn(createModuleResult(null)); + + manager.getRelativeNeighbourhood(query); + + verify(module).getNeighbourhood(query); + } +} diff --git a/TF_Exploitation_Server_core/src/test/java/net/disy/eenvplus/tfes/core/util/CollectionUtilitiesTest.java b/TF_Exploitation_Server_core/src/test/java/net/disy/eenvplus/tfes/core/util/CollectionUtilitiesTest.java index 9654614..5004b43 100644 --- a/TF_Exploitation_Server_core/src/test/java/net/disy/eenvplus/tfes/core/util/CollectionUtilitiesTest.java +++ b/TF_Exploitation_Server_core/src/test/java/net/disy/eenvplus/tfes/core/util/CollectionUtilitiesTest.java @@ -1,6 +1,8 @@ package net.disy.eenvplus.tfes.core.util; import static java.util.Arrays.asList; +import static java.util.Collections.emptyList; +import static net.disy.eenvplus.tfes.core.util.CollectionUtilities.first; import static net.disy.eenvplus.tfes.core.util.CollectionUtilities.flatten; import static net.disy.eenvplus.tfes.core.util.CollectionUtilities.limitResults; import static org.hamcrest.Matchers.contains; @@ -11,6 +13,7 @@ import static org.hamcrest.Matchers.startsWith; import static org.junit.Assert.assertThat; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; @@ -29,32 +32,32 @@ public class CollectionUtilitiesTest { public ExpectedException thrown = ExpectedException.none(); @Test - public void emptyCollection() throws Exception { + public void flattenEmptyCollection() throws Exception { Collection result = flatten(Collections.> emptyList()); assertThat(result, is(empty())); } @Test - public void collectionOfEmptyCollection() throws Exception { + public void flattenCollectionOfEmptyCollection() throws Exception { Collection result = flatten(asList(EMPTY_LIST_OF_OBJECT)); assertThat(result, is(empty())); } @Test - public void collectionOfTwoEmptyCollections() throws Exception { + public void flattenCollectionOfTwoEmptyCollections() throws Exception { Collection result = flatten(asList(EMPTY_LIST_OF_OBJECT, EMPTY_LIST_OF_OBJECT)); assertThat(result, is(empty())); } @Test - public void collectionOfSingleCollection() throws Exception { + public void flattenCollectionOfSingleCollection() throws Exception { List list = asList(new Object(), new Object()); Collection result = flatten(asList(list)); assertThat(result, containsInAnyOrder(list.toArray())); } @Test - public void collectionOfTwoCollections() throws Exception { + public void flattenCollectionOfTwoCollections() throws Exception { Object thisItem = new Object(); Object thatItem = new Object(); List list1 = asList(thisItem, thatItem); @@ -101,4 +104,23 @@ public void limitToExactLengthReturnsUnchanged() throws Exception { assertThat(result, is((equalTo(TEST_LIST)))); } + @Test + public void firstOfEmptyCollectionReturnsAlternative() throws Exception { + Object alternative = new Object(); + + Object result = first(emptyList(), alternative); + + assertThat(result, is(alternative)); + } + + @Test + public void firstOfCollectionReturnsFirst() throws Exception { + Object first = new Object(); + Object second = new Object(); + + Object result = first(Arrays.asList(first, second), null); + + assertThat(result, is(first)); + } + } diff --git a/TF_Exploitation_Server_modules/pom.xml b/TF_Exploitation_Server_modules/pom.xml index 2eba99f..6db7b83 100644 --- a/TF_Exploitation_Server_modules/pom.xml +++ b/TF_Exploitation_Server_modules/pom.xml @@ -7,19 +7,19 @@ net.disy.eenvplus eenvplus-tf-exploitation-server-parent - 0.3.3-SNAPSHOT + 0.4.4-SNAPSHOT net.disy.eenvplus eenvplus-tf-exploitation-server-core - 0.3.3-SNAPSHOT + 0.4.4-SNAPSHOT net.disy.eenvplus eenvplus-tf-exploitation-server-core - 0.3.3-SNAPSHOT + 0.4.4-SNAPSHOT test-jar test diff --git a/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/configuration/ServiceModuleConfiguration.java b/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/configuration/ServiceModuleConfiguration.java index b18affa..95895ba 100644 --- a/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/configuration/ServiceModuleConfiguration.java +++ b/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/configuration/ServiceModuleConfiguration.java @@ -2,6 +2,7 @@ package net.disy.eenvplus.tfes.modules.configuration; import net.disy.eenvplus.tfes.core.api.modules.IDescriptionProviderServiceModule; +import net.disy.eenvplus.tfes.core.api.modules.IRelativeNeighbourhoodProviderServiceModule; import net.disy.eenvplus.tfes.core.api.modules.IRelativeProviderServiceModule; import net.disy.eenvplus.tfes.core.api.modules.IResolveThesaurusProviderServiceModule; import net.disy.eenvplus.tfes.core.api.modules.ISuggestionProviderServiceModule; @@ -14,6 +15,7 @@ import net.disy.eenvplus.tfes.modules.keyword.translation.crosswalking.KeywordTranslationCrossWalkingModule; import net.disy.eenvplus.tfes.modules.semantic.explorative.search.SemanticExplorativeSearchModule; import net.disy.eenvplus.tfes.modules.semantic.explorative.search.crosswalking.SemanticExplorativeSearchCrossWalkingModule; +import net.disy.eenvplus.tfes.modules.semantic.neighbourhood.RelativeNeighbourhoodModule; import net.disy.eenvplus.tfes.modules.thesaurus.resolution.ThesaurusResolutionModule; import net.disy.eenvplus.tfes.modules.topmost.TopMostConceptModule; @@ -78,4 +80,10 @@ public ITopMostConceptProviderServiceModule topMostConceptModule() { return new TopMostConceptModule(); } + @Bean + @ConfiguredByEnvironmentProperty("use.semantic.neighbourhood.module") + public IRelativeNeighbourhoodProviderServiceModule relativeNeighbourhoodModule() { + return new RelativeNeighbourhoodModule(); + } + } diff --git a/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/core/ThesaurusSparqlConnector.java b/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/core/ThesaurusSparqlConnector.java index d01ee01..0475fd2 100644 --- a/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/core/ThesaurusSparqlConnector.java +++ b/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/core/ThesaurusSparqlConnector.java @@ -1,6 +1,7 @@ //Copyright (c) 2014 by Disy Informationssysteme GmbH package net.disy.eenvplus.tfes.modules.core; +import static org.apache.commons.lang3.StringUtils.isNotBlank; import net.disy.eenvplus.tfes.core.api.exceptions.ServiceException; import org.slf4j.Logger; @@ -20,24 +21,47 @@ public class ThesaurusSparqlConnector implements ISparqlConnector { @Value("${sparql.endpoint.url}") private String sparqlEndpointUrl; + private static final Logger LOGGER = LoggerFactory.getLogger(ThesaurusSparqlConnector.class); @Override public ResultSet executeSparqlQuery(Query query) throws ServiceException { - LOGGER.debug("Executing SparQl-Query:\n" + query.toString()); //$NON-NLS-1$ + logQuery(query); QueryExecution queryExecution = QueryExecutionFactory.sparqlService(sparqlEndpointUrl, query); try { ResultSet result = queryExecution.execSelect(); + logResult(query, result); return result; } catch (QueryExceptionHTTP exception) { - LOGGER - .error("Error in Request to SPARQL endpoint. Response-Code: " + exception.getResponseCode()); //$NON-NLS-1$ - + StringBuilder builder = new StringBuilder(); + builder.append('[').append(query.hashCode()).append(']'); + builder.append(" Error in Request to SPARQL endpoint. Response-Code: "); //$NON-NLS-1$ + builder.append(exception.getResponseCode()); + appendMessage(builder, exception.getResponseMessage()); + appendMessage(builder, exception.getLocalizedMessage()); + LOGGER.error(builder.toString()); throw SparqlExceptionFactory.wrap(sparqlEndpointUrl, exception); } } + @SuppressWarnings("nls") + private void logQuery(Query query) { + LOGGER.debug("[" + query.hashCode() + "]" + " Executing SparQl-Query:\n" + query.toString()); + } + + @SuppressWarnings("nls") + private void logResult(Query query, ResultSet result) { + LOGGER.debug("[" + query.hashCode() + "]" + " Successfully received SparQl Response."); + } + + private void appendMessage(StringBuilder builder, String message) { + if (isNotBlank(message)) { + builder.append('\n'); + builder.append(message); + } + } + @Override public String getEndpointUrl() { return sparqlEndpointUrl; diff --git a/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/data/DataSourceConfigurationProviderServiceModule.java b/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/data/DataSourceConfigurationProviderServiceModule.java index 1879b20..89efc59 100644 --- a/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/data/DataSourceConfigurationProviderServiceModule.java +++ b/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/data/DataSourceConfigurationProviderServiceModule.java @@ -67,10 +67,10 @@ private Query createQuery() { Query query = QueryFactory.create(); query.setQuerySelectType(); query.setDistinct(true); - query.addResultVar(CONCEPT_SCHEME.getLabel()); - query.addResultVar(LANGUAGE.getLabel()); - query.addResultVar(LABEL.getLabel()); - query.addResultVar(SORT_PRIORITY.getLabel()); + query.addResultVar(CONCEPT_SCHEME.getName()); + query.addResultVar(LANGUAGE.getName()); + query.addResultVar(LABEL.getName()); + query.addResultVar(SORT_PRIORITY.getName()); query.setQueryPattern(createBody()); return query; } @@ -109,10 +109,10 @@ private List map(ResultSet result) { private IDataSourceConfiguration map(QuerySolution current) { DataSourceConfiguration result = new DataSourceConfiguration(); - result.setName(current.getLiteral(LABEL.getLabel()).getString()); - result.setOnlineResource(current.get(CONCEPT_SCHEME.getLabel()).asResource().getURI()); - result.setLanguages(asList(current.getLiteral(LANGUAGE.getLabel()).getString())); - result.setRank(current.getLiteral(SORT_PRIORITY.getLabel()).getDouble()); + result.setName(current.getLiteral(LABEL.getName()).getString()); + result.setOnlineResource(current.get(CONCEPT_SCHEME.getName()).asResource().getURI()); + result.setLanguages(asList(current.getLiteral(LANGUAGE.getName()).getString())); + result.setRank(current.getLiteral(SORT_PRIORITY.getName()).getDouble()); return result; } diff --git a/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/keyword/completion/SuggestionSparqlQueryBuilder.java b/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/keyword/completion/SuggestionSparqlQueryBuilder.java index 0845358..eaa3d06 100644 --- a/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/keyword/completion/SuggestionSparqlQueryBuilder.java +++ b/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/keyword/completion/SuggestionSparqlQueryBuilder.java @@ -33,7 +33,9 @@ private SuggestionSparqlQueryBuilder(String keyword, String sourceLabel) { this.sourceLabel = sourceLabel; } - public static SuggestionSparqlQueryBuilder createSuggestionQuery(String keyword, String sourceLabel) { + public static SuggestionSparqlQueryBuilder createSuggestionQuery( + String keyword, + String sourceLabel) { return new SuggestionSparqlQueryBuilder(keyword, sourceLabel); } @@ -73,7 +75,7 @@ protected SparqlQueryBuilder adapt(SparqlQueryBuilder builder) { return builder .addResultVariable(LABEL) .addResultVariable(CONCEPT) - .addResultVariable(sourceLabel); + .addResultVariable(sourceLabel, sourceActive); } } diff --git a/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/keyword/completion/crosswalking/FullSuggestionRankComparator.java b/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/keyword/completion/crosswalking/FullSuggestionRankComparator.java index 2fb9b20..f521e9e 100644 --- a/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/keyword/completion/crosswalking/FullSuggestionRankComparator.java +++ b/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/keyword/completion/crosswalking/FullSuggestionRankComparator.java @@ -1,11 +1,14 @@ //Copyright (c) 2014 by Disy Informationssysteme GmbH package net.disy.eenvplus.tfes.modules.keyword.completion.crosswalking; +import java.io.Serializable; import java.util.Comparator; // NOT_PUBLISHED -public class FullSuggestionRankComparator implements Comparator { +public class FullSuggestionRankComparator implements Comparator, Serializable { + + private static final long serialVersionUID = 1L; @Override public int compare(FullSuggestion left, FullSuggestion right) { diff --git a/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/keyword/completion/crosswalking/SuggestionCrossWalkingSparqlQueryBuilder.java b/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/keyword/completion/crosswalking/SuggestionCrossWalkingSparqlQueryBuilder.java index aa91019..b1c9647 100644 --- a/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/keyword/completion/crosswalking/SuggestionCrossWalkingSparqlQueryBuilder.java +++ b/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/keyword/completion/crosswalking/SuggestionCrossWalkingSparqlQueryBuilder.java @@ -96,7 +96,7 @@ protected SparqlQueryBuilder adapt(SparqlQueryBuilder builder) { .addResultVariable(CONCEPT) .addResultVariable(EXACT_MATCH) .addResultVariable(SORT_PRIORITY) - .addResultVariable(sourceLabel); + .addResultVariable(sourceLabel, sourceActive); } } diff --git a/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/keyword/explanation/CrossWalkingSimpleExplanationQueryBuilder.java b/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/keyword/explanation/CrossWalkingSimpleExplanationQueryBuilder.java index fe15b2a..8e021dc 100644 --- a/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/keyword/explanation/CrossWalkingSimpleExplanationQueryBuilder.java +++ b/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/keyword/explanation/CrossWalkingSimpleExplanationQueryBuilder.java @@ -88,7 +88,7 @@ private Element createRelatedMatchElement(SparqlNodes relation, SparqlNodes matc .add(createSchemeTriple(OBJECT, IN_SCHEME)) .build(); Query subQuery = createSelectQuery() - .addResultVariable(CONCEPT.getLabel(), getConceptUriExpr()) + .addResultVariable(CONCEPT.getName(), getConceptUriExpr()) .addResultVariable(PREDICATE.getName(), match.createUriValueNode()) .addResultVariable(OBJECT) .withBody(body) @@ -99,7 +99,7 @@ private Element createRelatedMatchElement(SparqlNodes relation, SparqlNodes matc @Override protected SparqlQueryBuilder adapt(SparqlQueryBuilder builder) { return builder - .addResultVariable(CONCEPT.getLabel(), getConceptUriExpr()) + .addResultVariable(CONCEPT.getName(), getConceptUriExpr()) .addResultVariable(PREDICATE) .addResultVariable(OBJECT); } diff --git a/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/keyword/explanation/CrossWalkingSourceExplanationQueryBuilder.java b/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/keyword/explanation/CrossWalkingSourceExplanationQueryBuilder.java index d8ec0b7..724dd1e 100644 --- a/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/keyword/explanation/CrossWalkingSourceExplanationQueryBuilder.java +++ b/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/keyword/explanation/CrossWalkingSourceExplanationQueryBuilder.java @@ -92,7 +92,7 @@ private Element createRelatedMatchElement(SparqlNodes relation, SparqlNodes matc .add(createSourceTriple(IN_SCHEME, SOURCE.getName())) .build(); Query subQuery = createSelectQuery() - .addResultVariable(CONCEPT.getLabel(), getConceptUriExpr()) + .addResultVariable(CONCEPT.getName(), getConceptUriExpr()) .addResultVariable(PREDICATE.getName(), match.createUriValueNode()) .addResultVariable(OBJECT) .addResultVariable(SOURCE) @@ -104,7 +104,7 @@ private Element createRelatedMatchElement(SparqlNodes relation, SparqlNodes matc @Override protected SparqlQueryBuilder adapt(SparqlQueryBuilder builder) { return builder - .addResultVariable(CONCEPT.getLabel(), getConceptUriExpr()) + .addResultVariable(CONCEPT.getName(), getConceptUriExpr()) .addResultVariable(PREDICATE) .addResultVariable(OBJECT) .addResultVariable(SOURCE); diff --git a/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/keyword/explanation/SimpleExplanationQueryBuilder.java b/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/keyword/explanation/SimpleExplanationQueryBuilder.java index e0bf512..70b763e 100644 --- a/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/keyword/explanation/SimpleExplanationQueryBuilder.java +++ b/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/keyword/explanation/SimpleExplanationQueryBuilder.java @@ -46,7 +46,7 @@ protected Element createBody() { @Override protected SparqlQueryBuilder adapt(SparqlQueryBuilder builder) { return builder - .addResultVariable(CONCEPT.getLabel(), getConceptUriExpr()) + .addResultVariable(CONCEPT.getName(), getConceptUriExpr()) .addResultVariable(PREDICATE) .addResultVariable(OBJECT); } diff --git a/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/keyword/explanation/SourceExplanationQueryBuilder.java b/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/keyword/explanation/SourceExplanationQueryBuilder.java index 20087f2..7ffaf82 100644 --- a/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/keyword/explanation/SourceExplanationQueryBuilder.java +++ b/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/keyword/explanation/SourceExplanationQueryBuilder.java @@ -50,7 +50,7 @@ protected Element createBody() { @Override protected SparqlQueryBuilder adapt(SparqlQueryBuilder builder) { return builder - .addResultVariable(CONCEPT.getLabel(), new NodeValueNode(createURI(getConceptUri()))) + .addResultVariable(CONCEPT.getName(), new NodeValueNode(createURI(getConceptUri()))) .addResultVariable(PREDICATE) .addResultVariable(OBJECT) .addResultVariable(SOURCE); diff --git a/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/keyword/translation/SynonymsQueryBuilder.java b/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/keyword/translation/SynonymsQueryBuilder.java index c6fb88a..f4aecaf 100644 --- a/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/keyword/translation/SynonymsQueryBuilder.java +++ b/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/keyword/translation/SynonymsQueryBuilder.java @@ -49,9 +49,9 @@ protected SynonymsQueryBuilder getThis() { @Override protected SparqlQueryBuilder adapt(SparqlQueryBuilder builder) { return builder - .addResultVariable(CONCEPT.getLabel()) - .addResultVariable(LABEL.getLabel()) - .addResultVariable(sourceLabel); + .addResultVariable(CONCEPT.getName()) + .addResultVariable(LABEL.getName()) + .addResultVariable(sourceLabel, sourceActive); } @Override diff --git a/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/keyword/translation/crosswalking/SynonymsCrossWalkingQueryBuilder.java b/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/keyword/translation/crosswalking/SynonymsCrossWalkingQueryBuilder.java index 7530fd1..59d278c 100644 --- a/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/keyword/translation/crosswalking/SynonymsCrossWalkingQueryBuilder.java +++ b/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/keyword/translation/crosswalking/SynonymsCrossWalkingQueryBuilder.java @@ -59,9 +59,9 @@ public static SynonymsCrossWalkingQueryBuilder createSynonymsQuery( @Override protected SparqlQueryBuilder adapt(SparqlQueryBuilder builder) { return builder - .addResultVariable(CONCEPT.getLabel()) - .addResultVariable(LABEL.getLabel()) - .addResultVariable(sourceLabel); + .addResultVariable(CONCEPT.getName()) + .addResultVariable(LABEL.getName()) + .addResultVariable(sourceLabel, sourceActive); } @Override diff --git a/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/semantic/explorative/search/RelativesQueryBuilder.java b/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/semantic/explorative/search/RelativesQueryBuilder.java index ae87d22..2daa32f 100644 --- a/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/semantic/explorative/search/RelativesQueryBuilder.java +++ b/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/semantic/explorative/search/RelativesQueryBuilder.java @@ -57,10 +57,10 @@ protected RelativesQueryBuilder getThis() { @Override protected SparqlQueryBuilder adapt(SparqlQueryBuilder builder) { return builder - .addResultVariable(CONCEPT.getLabel()) - .addResultVariable(LABEL.getLabel()) - .addResultVariable(RELATION.getLabel()) - .addResultVariable(sourceLabel); + .addResultVariable(CONCEPT.getName()) + .addResultVariable(LABEL.getName()) + .addResultVariable(RELATION.getName()) + .addResultVariable(sourceLabel, sourceActive); } @Override diff --git a/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/semantic/explorative/search/crosswalking/RelativesCrossWalkingQueryBuilder.java b/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/semantic/explorative/search/crosswalking/RelativesCrossWalkingQueryBuilder.java index b0e3645..940633d 100644 --- a/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/semantic/explorative/search/crosswalking/RelativesCrossWalkingQueryBuilder.java +++ b/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/semantic/explorative/search/crosswalking/RelativesCrossWalkingQueryBuilder.java @@ -65,10 +65,10 @@ protected RelativesCrossWalkingQueryBuilder getThis() { @Override protected SparqlQueryBuilder adapt(SparqlQueryBuilder builder) { return builder - .addResultVariable(CONCEPT.getLabel()) - .addResultVariable(LABEL.getLabel()) - .addResultVariable(RELATION.getLabel()) - .addResultVariable(sourceLabel); + .addResultVariable(CONCEPT.getName()) + .addResultVariable(LABEL.getName()) + .addResultVariable(RELATION.getName()) + .addResultVariable(sourceLabel, sourceActive); } @Override @@ -91,7 +91,7 @@ private ElementUnion createRelations() { } private ElementSubQuery createSubQuery(SparqlNodes relation, SparqlNodes match) { - Query subQuery = createRelationQuery(concept, RELATION.getLabel(), CONCEPT.getLabel()) + Query subQuery = createRelationQuery(concept, RELATION.getName(), CONCEPT.getName()) .withRelation(relation) .withMatch(match) .createQuery(); diff --git a/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/semantic/neighbourhood/ConceptUriSourceLabelProvider.java b/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/semantic/neighbourhood/ConceptUriSourceLabelProvider.java new file mode 100644 index 0000000..cd7b1e9 --- /dev/null +++ b/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/semantic/neighbourhood/ConceptUriSourceLabelProvider.java @@ -0,0 +1,87 @@ +//Copyright (c) 2015 by Disy Informationssysteme GmbH +package net.disy.eenvplus.tfes.modules.semantic.neighbourhood; + +import static com.hp.hpl.jena.graph.NodeFactory.createURI; +import static net.disy.eenvplus.tfes.modules.sparql.element.ElementGroupBuilder.createGroup; +import static net.disy.eenvplus.tfes.modules.sparql.element.SparqlElementFactory.createSchemeTriple; +import static net.disy.eenvplus.tfes.modules.sparql.element.SparqlElementFactory.createSourceTriple; +import static net.disy.eenvplus.tfes.modules.sparql.query.SparqlNodes.IN_SCHEME; +import static net.disy.eenvplus.tfes.modules.sparql.query.SparqlQueryBuilder.createSelectDistinctQuery; +import static org.apache.commons.lang3.StringUtils.EMPTY; + +import java.util.concurrent.ConcurrentHashMap; + +import net.disy.eenvplus.tfes.core.api.exceptions.ServiceException; +import net.disy.eenvplus.tfes.modules.core.ISparqlConnector; +import net.disy.eenvplus.tfes.modules.sparql.result.ISourceLabelProvider; +import net.disy.eenvplus.tfes.modules.sparql.result.QuerySolutionItemExtractors; + +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import com.hp.hpl.jena.graph.Node; +import com.hp.hpl.jena.graph.NodeFactory; +import com.hp.hpl.jena.query.Query; +import com.hp.hpl.jena.query.ResultSet; +import com.hp.hpl.jena.sparql.syntax.Element; + +// NOT_PUBLISHED +@Service +public class ConceptUriSourceLabelProvider implements ISourceLabelProvider { + + private static final String LABEL = "label"; //$NON-NLS-1$ + + private static final Logger LOGGER = LoggerFactory.getLogger(ConceptUriSourceLabelProvider.class); + + @Autowired + private ISparqlConnector sparqlConnector; + + private ConcurrentHashMap labels = new ConcurrentHashMap<>(); + + @Override + public String provideFor(String uri) { + if (StringUtils.isBlank(uri)) { + return null; + } + String key = extractSourceKey(uri); + if (labels.get(key) == null) { + return retrieveLabel(uri); + } + return labels.get(key); + } + + private String retrieveLabel(String uri) { + Query query = createQuery(uri); + String result = EMPTY; + try { + ResultSet resultSet = sparqlConnector.executeSparqlQuery(query); + if (resultSet.hasNext()) { + result = QuerySolutionItemExtractors.getLabel(LABEL, resultSet.next()); + } + labels.putIfAbsent(extractSourceKey(uri), result); + LOGGER.debug("Added to source label cache: " + extractSourceKey(uri) + " -> " + result); //$NON-NLS-1$//$NON-NLS-2$ + } + catch (ServiceException logged) { + LOGGER.warn("Cannot retrieve source label for concept " + uri, logged); //$NON-NLS-1$ + } + return result; + + } + + private Query createQuery(String uri) { + Node label = NodeFactory.createVariable(LABEL); + Element body = createGroup() + .add(createSchemeTriple(createURI(uri), IN_SCHEME)) + .add(createSourceTriple(IN_SCHEME, label)) + .build(); + return createSelectDistinctQuery().addResultVariable(label).withBody(body).getQuery(); + } + + private String extractSourceKey(String uri) { + return uri.substring(0, uri.lastIndexOf('/')); + } + +} diff --git a/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/semantic/neighbourhood/Nodes.java b/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/semantic/neighbourhood/Nodes.java new file mode 100644 index 0000000..f16103d --- /dev/null +++ b/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/semantic/neighbourhood/Nodes.java @@ -0,0 +1,27 @@ +//Copyright (c) 2015 by Disy Informationssysteme GmbH +package net.disy.eenvplus.tfes.modules.semantic.neighbourhood; + +import com.hp.hpl.jena.graph.Node; +import com.hp.hpl.jena.graph.NodeFactory; + +enum Nodes { + CONCEPT("concept"), //$NON-NLS-1$ + RELATION("relation"), //$NON-NLS-1$ + SOURCE("source"); //$NON-NLS-1$ + + private static final String LABEL_INFIX = "Label"; //$NON-NLS-1$ + + private String prefix; + + private Nodes(String prefix) { + this.prefix = prefix; + } + + public Node getNode(int level) { + return NodeFactory.createVariable(prefix + level); + } + + public Node getLabelNode(int level) { + return NodeFactory.createVariable(prefix + LABEL_INFIX + level); + } +} \ No newline at end of file diff --git a/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/semantic/neighbourhood/RelativeNeighbourhoodModule.java b/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/semantic/neighbourhood/RelativeNeighbourhoodModule.java new file mode 100644 index 0000000..09e46d9 --- /dev/null +++ b/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/semantic/neighbourhood/RelativeNeighbourhoodModule.java @@ -0,0 +1,76 @@ +//Copyright (c) 2015 by Disy Informationssysteme GmbH +package net.disy.eenvplus.tfes.modules.semantic.neighbourhood; + +import static net.disy.eenvplus.tfes.core.api.query.QueryParameterKeys.QUERY_DEPTH; +import static net.disy.eenvplus.tfes.core.api.query.QueryParameterKeys.RELATIONS; +import static net.disy.eenvplus.tfes.modules.semantic.neighbourhood.RelativeNeighbourhoodQueryBuilder.createRelativeNeighbourhoodQuery; + +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.Callable; + +import net.disy.eenvplus.tfes.core.api.capabilities.ParameterDescription; +import net.disy.eenvplus.tfes.core.api.capabilities.ServiceModuleDescription; +import net.disy.eenvplus.tfes.core.api.exceptions.ServiceException; +import net.disy.eenvplus.tfes.core.api.modules.IRelativeNeighbourhoodProviderServiceModule; +import net.disy.eenvplus.tfes.core.api.query.IConceptQuery; +import net.disy.eenvplus.tfes.core.api.response.IVisualizationNode; +import net.disy.eenvplus.tfes.modules.core.ISparqlConnector; + +import org.springframework.beans.factory.annotation.Autowired; + +import com.hp.hpl.jena.query.Query; +import com.hp.hpl.jena.query.ResultSet; + +// NOT_PUBLISHED +public class RelativeNeighbourhoodModule implements IRelativeNeighbourhoodProviderServiceModule { + + private static final String SERVICE_ID = "Relative Neighbourhood Module"; //$NON-NLS-1$ + private static final ParameterDescription DEPTH_PARAMETER = new ParameterDescription( + QUERY_DEPTH.getKey(), + "integer", 3); //$NON-NLS-1$ + private static final ParameterDescription RELATIONS_PARAMETER = new ParameterDescription( + RELATIONS.getKey(), + "string", ""); //$NON-NLS-1$ //$NON-NLS-2$ + + @Autowired + private ISparqlConnector sparqlConnector; + + @Autowired + private RelativeNeighbourhoodResultSetMapper resultMapper; + + @Override + public ServiceModuleDescription getDescription() { + List parameterDescriptions = Arrays.asList( + DEPTH_PARAMETER, + RELATIONS_PARAMETER); + return new ServiceModuleDescription(SERVICE_ID, parameterDescriptions); + } + + @Override + public Callable getNeighbourhood(final IConceptQuery query) { + + return new Callable() { + + @Override + public IVisualizationNode call() throws ServiceException { + Query jenaQuery = createRelativeNeighbourhoodQuery(query.getConcept()) + .withLanguages(query.getLanguages()) + .withRelations(getRelations(query)) + .withDepth(getDepth(query)) + .build(); + ResultSet resultSet = sparqlConnector.executeSparqlQuery(jenaQuery); + return resultMapper.map(resultSet, getDepth(query)); + } + + @SuppressWarnings("unchecked") + private List getRelations(IConceptQuery query) { + return (List) query.getExtraParameters().get(RELATIONS.getKey()); + } + + private Integer getDepth(final IConceptQuery query) { + return (Integer) query.getExtraParameters().get(QUERY_DEPTH.getKey()); + } + }; + } +} diff --git a/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/semantic/neighbourhood/RelativeNeighbourhoodQueryBuilder.java b/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/semantic/neighbourhood/RelativeNeighbourhoodQueryBuilder.java new file mode 100644 index 0000000..837ba86 --- /dev/null +++ b/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/semantic/neighbourhood/RelativeNeighbourhoodQueryBuilder.java @@ -0,0 +1,209 @@ +//Copyright (c) 2015 by Disy Informationssysteme GmbH +package net.disy.eenvplus.tfes.modules.semantic.neighbourhood; + +import static java.util.Arrays.asList; +import static net.disy.eenvplus.tfes.modules.sparql.element.ElementGroupBuilder.createGroup; +import static net.disy.eenvplus.tfes.modules.sparql.expression.SparqlExpressionFactory.createMultipleOptionsExpression; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import net.disy.eenvplus.tfes.core.api.exceptions.UnknownRelationException; +import net.disy.eenvplus.tfes.modules.sparql.element.ElementGroupBuilder; +import net.disy.eenvplus.tfes.modules.sparql.expression.SparqlExpressionBuilder; +import net.disy.eenvplus.tfes.modules.sparql.expression.SparqlLanguageExpression; +import net.disy.eenvplus.tfes.modules.sparql.expression.SparqlUriExpression; +import net.disy.eenvplus.tfes.modules.sparql.query.AbstractQueryBuilder; +import net.disy.eenvplus.tfes.modules.sparql.query.SparqlNodes; +import net.disy.eenvplus.tfes.modules.sparql.query.SparqlQueryBuilder; + +import com.hp.hpl.jena.graph.Node; +import com.hp.hpl.jena.graph.NodeFactory; +import com.hp.hpl.jena.graph.Triple; +import com.hp.hpl.jena.sparql.expr.E_NotEquals; +import com.hp.hpl.jena.sparql.expr.nodevalue.NodeValueNode; +import com.hp.hpl.jena.sparql.syntax.Element; +import com.hp.hpl.jena.sparql.syntax.ElementGroup; + +// NOT_PUBLISHED +public class RelativeNeighbourhoodQueryBuilder + extends + AbstractQueryBuilder { + + private static final int DEFAULT_DEPTH = 3; + private static final List ALL_RELATIONS = asList( + SparqlNodes.RELATED, + SparqlNodes.BROADER, + SparqlNodes.NARROWER, + SparqlNodes.EXACT_MATCH, + SparqlNodes.CLOSE_MATCH); + + private Node rootNode; + private int depth = DEFAULT_DEPTH; + private Collection relations = ALL_RELATIONS; + + private RelativeNeighbourhoodQueryBuilder(String rootConcept) { + this.rootNode = NodeFactory.createURI(rootConcept); + } + + public static RelativeNeighbourhoodQueryBuilder createRelativeNeighbourhoodQuery( + String rootConcept) { + return new RelativeNeighbourhoodQueryBuilder(rootConcept); + } + + public RelativeNeighbourhoodQueryBuilder withDepth(int depth) { + this.depth = depth; + return this; + } + + public RelativeNeighbourhoodQueryBuilder withRelations(List relations) + throws UnknownRelationException { + if (relations == null || relations.isEmpty()) { + return this; + } + this.relations = new ArrayList<>(relations.size()); + for (String current : relations) { + SparqlNodes node = getNode(current); + this.relations.add(node); + } + return this; + } + + private SparqlNodes getNode(String current) throws UnknownRelationException { + SparqlNodes node = SparqlNodes.parseName(current); + if (node == null) { + throw new UnknownRelationException(current); + } + return node; + } + + @Override + protected RelativeNeighbourhoodQueryBuilder getThis() { + return this; + } + + @Override + protected Element createBody() { + ElementGroupBuilder groupBuilder = ElementGroupBuilder.createGroup(); + groupBuilder = addRootTriple(groupBuilder); + if (depth > 0) { + groupBuilder = addDeeperLevelTriples(groupBuilder); + } + return groupBuilder.build(); + } + + private ElementGroupBuilder addRootTriple(ElementGroupBuilder groupBuilder) { + Triple rootLabelTriple = new Triple( + rootNode, + SparqlNodes.PREF_LABEL.createUriNode(), + Nodes.CONCEPT.getLabelNode(0)); + return groupBuilder.addOptional(createConceptLabelGroup(0, rootLabelTriple)); + } + + private ElementGroupBuilder addDeeperLevelTriples(ElementGroupBuilder groupBuilder) { + ElementGroup previous = addLevelElements(createGroup(), depth, getConceptNode(depth - 1)) + .build(); + for (int currentIndex = depth - 1; currentIndex >= 1; currentIndex--) { + previous = addLevelElements(createGroup(), currentIndex, getConceptNode(currentIndex - 1)) + .addOptional(previous) + .build(); + } + return groupBuilder.addOptional(previous); + } + + private Node getConceptNode(int level) { + if (level == 0) { + return rootNode; + } + return Nodes.CONCEPT.getNode(level); + } + + private ElementGroupBuilder addLevelElements(ElementGroupBuilder builder, int level, Node parent) { + SparqlExpressionBuilder filterBuilder = SparqlExpressionBuilder + .use(createMultipleOptionsExpression( + new SparqlUriExpression(Nodes.RELATION.getNode(level)), + getNeighbourhoodRelationUris())); + filterBuilder = addConceptFilters(filterBuilder, level); + builder + .add(createRelationTriple(level, parent)) + .add(createIsMaterializedConceptTriple(level)) + .addAsFilter(filterBuilder.toExpr()); + return builder.addOptional(createConceptLabelGroup(level)); + } + + private Triple createIsMaterializedConceptTriple(int level) { + Node anonymousNode = NodeFactory.createVariable("a" + level); //$NON-NLS-1$ + return Triple.create( + Nodes.CONCEPT.getNode(level), + anonymousNode, + SparqlNodes.CONCEPT.createUriNode()); + } + + private SparqlExpressionBuilder addConceptFilters(SparqlExpressionBuilder filterBuilder, int level) { + for (int currentIndex = 0; currentIndex < level; currentIndex++) { + filterBuilder.and(createDifferentNodesExpression( + getConceptNode(currentIndex), + getConceptNode(level))); + } + return filterBuilder; + } + + private ElementGroup createConceptLabelGroup(int level) { + return createConceptLabelGroup(level, createConceptLabelTriple(level)); + } + + private ElementGroup createConceptLabelGroup(int level, Triple conceptLabelTriple) { + return createGroup() + .add(conceptLabelTriple) + .addAsFilter( + createMultipleOptionsExpression( + new SparqlLanguageExpression(Nodes.CONCEPT.getLabelNode(level)), + getLanguages()), + !getLanguages().isEmpty()) + .build(); + } + + private Triple createConceptLabelTriple(int level) { + return createLabelNodeTriple(level, Nodes.CONCEPT, SparqlNodes.PREF_LABEL); + } + + private Triple createRelationTriple(int level, Node parent) { + return Triple.create(parent, Nodes.RELATION.getNode(level), getConceptNode(level)); + } + + private Triple createLabelNodeTriple(int level, Nodes node, SparqlNodes labelNode) { + return Triple.create(node.getNode(level), labelNode.createUriNode(), node.getLabelNode(level)); + } + + private E_NotEquals createDifferentNodesExpression(Node left, Node right) { + return new E_NotEquals(new NodeValueNode(left), new NodeValueNode(right)); + } + + private List getNeighbourhoodRelationUris() { + List relationUris = new ArrayList(relations.size()); + for (SparqlNodes current : relations) { + relationUris.add(current.getUri()); + } + return relationUris; + } + + @Override + protected SparqlQueryBuilder adapt(SparqlQueryBuilder builder) { + builder = builder.addResultVariable( + Nodes.CONCEPT.getNode(0).getName(), + new NodeValueNode(rootNode)).addResultVariable(Nodes.CONCEPT.getLabelNode(0)); + for (int currentIndex = 1; currentIndex <= depth; currentIndex++) { + builder = addResultVariables(builder, currentIndex); + } + return builder; + } + + private SparqlQueryBuilder addResultVariables(SparqlQueryBuilder builder, int level) { + return builder + .addResultVariable(getConceptNode(level)) + .addResultVariable(Nodes.CONCEPT.getLabelNode(level)) + .addResultVariable(Nodes.RELATION.getNode(level)); + } + +} diff --git a/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/semantic/neighbourhood/RelativeNeighbourhoodResultSetMapper.java b/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/semantic/neighbourhood/RelativeNeighbourhoodResultSetMapper.java new file mode 100644 index 0000000..b2cbc71 --- /dev/null +++ b/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/semantic/neighbourhood/RelativeNeighbourhoodResultSetMapper.java @@ -0,0 +1,53 @@ +//Copyright (c) 2015 by Disy Informationssysteme GmbH +package net.disy.eenvplus.tfes.modules.semantic.neighbourhood; + +import java.util.ArrayList; +import java.util.List; + +import net.disy.eenvplus.tfes.core.api.response.IRelatedConcept; +import net.disy.eenvplus.tfes.core.api.response.IVisualizationNode; +import net.disy.eenvplus.tfes.modules.sparql.result.ISourceLabelProvider; +import net.disy.eenvplus.tfes.modules.sparql.result.ResultFactory; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import com.hp.hpl.jena.query.QuerySolution; +import com.hp.hpl.jena.query.ResultSet; + +// NOT_PUBLISHED +@Component +public final class RelativeNeighbourhoodResultSetMapper { + + @Autowired + private ISourceLabelProvider sourceLabelProvider; + + public IVisualizationNode map(ResultSet resultSet, Integer depth) { + if (!resultSet.hasNext()) { + return null; + } + RelativeNeighbourhoodResultTreeBuilder builder = RelativeNeighbourhoodResultTreeBuilder.empty(); + while (resultSet.hasNext()) { + QuerySolution current = resultSet.next(); + final List concepts = new ArrayList<>(depth); + for (int currentLevel = 0; currentLevel <= depth; currentLevel++) { + IRelatedConcept concept = getConcept(current, currentLevel); + if (concept != null) { + concepts.add(concept); + } + } + builder = builder.addConcepts(concepts); + } + return builder.build(); + } + + private IRelatedConcept getConcept(QuerySolution current, int level) { + return ResultFactory.createRelatedConcept( + current, + Nodes.CONCEPT.getNode(level), + Nodes.CONCEPT.getLabelNode(level), + Nodes.RELATION.getNode(level), + sourceLabelProvider); + } + +} diff --git a/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/semantic/neighbourhood/RelativeNeighbourhoodResultTreeBuilder.java b/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/semantic/neighbourhood/RelativeNeighbourhoodResultTreeBuilder.java new file mode 100644 index 0000000..4b9a750 --- /dev/null +++ b/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/semantic/neighbourhood/RelativeNeighbourhoodResultTreeBuilder.java @@ -0,0 +1,106 @@ +//Copyright (c) 2015 by Disy Informationssysteme GmbH +package net.disy.eenvplus.tfes.modules.semantic.neighbourhood; + +import java.util.List; +import java.util.Locale; + +import net.disy.eenvplus.tfes.core.api.response.IRelatedConcept; +import net.disy.eenvplus.tfes.core.api.response.IVisualizationNode; + +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +// NOT_PUBLISHED + +public final class RelativeNeighbourhoodResultTreeBuilder { + + private static final Logger LOGGER = LoggerFactory + .getLogger(RelativeNeighbourhoodResultTreeBuilder.class); + private VisualizationNode root = new VisualizationNode(); + + private RelativeNeighbourhoodResultTreeBuilder() { + } + + public static RelativeNeighbourhoodResultTreeBuilder empty() { + return new RelativeNeighbourhoodResultTreeBuilder(); + } + + public RelativeNeighbourhoodResultTreeBuilder addConcepts(List concepts) { + logAddConcept(concepts); + if (concepts.isEmpty()) { + return this; + } + if (hasNoRootElement() || hasRootElement(concepts.get(0))) { + root.setElement(concepts.get(0)); + addChildren(root, chopFirstConcept(concepts)); + } + return this; + } + + @SuppressWarnings("nls") + private void logAddConcept(List concepts) { + StringBuilder builder = new StringBuilder("Adding Concept String:\n"); + for (IRelatedConcept concept : concepts) { + builder.append('\t').append(concept.toString()).append('\n'); + } + LOGGER.trace(builder.toString()); + } + + private boolean hasNoRootElement() { + return root.getElement() == null; + } + + private boolean hasRootElement(IRelatedConcept concept) { + if (root.getElement() == null) { + return concept == null; + } + if (concept == null) { + return false; + } + IRelatedConcept rootConcept = root.getElement(); + return isSameConcept(rootConcept, concept); + } + + private static boolean isSameConcept(IRelatedConcept left, IRelatedConcept right) { + return StringUtils.equals(left.getConceptUri(), right.getConceptUri()) + && StringUtils.equals(left.getLabel(), right.getLabel()) + && isCompatibleLanguagePair(left.getLanguage(), right.getLanguage()); + } + + private static boolean isCompatibleLanguagePair(String left, String right) { + if (left == null || right == null) { + return StringUtils.equals(left, right); + } + String leftLanguage = mapToBaseLanguage(left); + String rightLanguage = mapToBaseLanguage(right); + return StringUtils.equals(leftLanguage, rightLanguage); + } + + private static String mapToBaseLanguage(String language) { + return Locale.forLanguageTag(language).getLanguage(); + } + + private static List chopFirstConcept(List concepts) { + return concepts.subList(1, concepts.size()); + } + + private static void addChildren(IVisualizationNode root, List toAdd) { + if (!toAdd.isEmpty()) { + for (IVisualizationNode child : root.getChildren()) { + if (isSameConcept(child.getElement(), toAdd.get(0))) { + addChildren(child, chopFirstConcept(toAdd)); + return; + } + } + if (root instanceof VisualizationNode) { + ((VisualizationNode) root).addChild(empty().addConcepts(toAdd).build()); + } + } + } + + public IVisualizationNode build() { + return root; + } + +} diff --git a/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/semantic/neighbourhood/VisualizationNode.java b/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/semantic/neighbourhood/VisualizationNode.java new file mode 100644 index 0000000..26768da --- /dev/null +++ b/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/semantic/neighbourhood/VisualizationNode.java @@ -0,0 +1,36 @@ +//Copyright (c) 2015 by Disy Informationssysteme GmbH +package net.disy.eenvplus.tfes.modules.semantic.neighbourhood; + +import java.util.Collection; +import java.util.LinkedList; +import java.util.List; + +import net.disy.eenvplus.tfes.core.api.response.IRelatedConcept; +import net.disy.eenvplus.tfes.core.api.response.IVisualizationNode; + +// NOT_PUBLISHED + +class VisualizationNode implements IVisualizationNode { + + private IRelatedConcept element; + private List children = new LinkedList<>(); + + public void setElement(IRelatedConcept element) { + this.element = element; + } + + public void addChild(IVisualizationNode node) { + children.add(node); + } + + @Override + public IRelatedConcept getElement() { + return element; + } + + @Override + public Collection getChildren() { + return children; + } + +} diff --git a/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/sparql/element/ElementGroupBuilder.java b/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/sparql/element/ElementGroupBuilder.java index 08eb48e..1c159fc 100644 --- a/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/sparql/element/ElementGroupBuilder.java +++ b/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/sparql/element/ElementGroupBuilder.java @@ -34,6 +34,11 @@ public ElementGroup build() { return group; } + public ElementGroupBuilder addOptional(Element optional) { + group.addElement(new ElementOptional(optional)); + return this; + } + public ElementGroupBuilder addOptional(Triple create) { ElementTriplesBlock block = new ElementTriplesBlock(); block.addTriple(create); @@ -53,4 +58,11 @@ public ElementGroupBuilder addAsFilter(Expr expression) { return this; } + public ElementGroupBuilder addAsFilter(Expr expression, boolean condition) { + if (condition) { + group.addElementFilter(new ElementFilter(expression)); + } + return this; + } + } diff --git a/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/sparql/element/SparqlElementFactory.java b/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/sparql/element/SparqlElementFactory.java index c25f20d..1f7d20f 100644 --- a/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/sparql/element/SparqlElementFactory.java +++ b/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/sparql/element/SparqlElementFactory.java @@ -46,7 +46,11 @@ public static Triple createPredicateVar(Node concept, SparqlNodes scheme) { } public static Triple createSourceTriple(SparqlNodes inScheme, String sourceLabel) { - return create(inScheme.createVar(), LABEL.createUriNode(), createVariable(sourceLabel)); + return createSourceTriple(inScheme, createVariable(sourceLabel)); + } + + public static Triple createSourceTriple(SparqlNodes inScheme, Node sourceLabel) { + return create(inScheme.createVar(), LABEL.createUriNode(), sourceLabel); } } diff --git a/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/sparql/query/SparqlNodes.java b/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/sparql/query/SparqlNodes.java index 42eda59..7a5c331 100644 --- a/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/sparql/query/SparqlNodes.java +++ b/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/sparql/query/SparqlNodes.java @@ -8,8 +8,6 @@ import java.util.Collection; import java.util.List; -import org.apache.commons.lang3.StringUtils; - import com.hp.hpl.jena.graph.Node; import com.hp.hpl.jena.graph.NodeFactory; import com.hp.hpl.jena.sparql.core.Var; @@ -23,30 +21,91 @@ // NOT_PUBLISHED public enum SparqlNodes { - BROADER("broader", "http://www.w3.org/2004/02/skos/core#broader"), //$NON-NLS-1$ //$NON-NLS-2$ - NARROWER("narrower", "http://www.w3.org/2004/02/skos/core#narrower"), //$NON-NLS-1$ //$NON-NLS-2$ - RELATED("related", "http://www.w3.org/2004/02/skos/core#related"), //$NON-NLS-1$ //$NON-NLS-2$ - PREF_LABEL("prefLabel", "http://www.w3.org/2004/02/skos/core#prefLabel"), //$NON-NLS-1$ //$NON-NLS-2$ - IN_SCHEME("schema", "http://www.w3.org/2004/02/skos/core#inScheme"), //$NON-NLS-1$ //$NON-NLS-2$ - CONCEPT("concept", "http://www.w3.org/2004/02/skos/core#Concept"), //$NON-NLS-1$ //$NON-NLS-2$ - CONCEPT_SCHEME("conceptScheme", "http://www.w3.org/2004/02/skos/core#ConceptScheme"), //$NON-NLS-1$ //$NON-NLS-2$ - RELATION("relation", ""), //$NON-NLS-1$ //$NON-NLS-2$ - LABEL("label", "http://www.w3.org/2000/01/rdf-schema#label"), //$NON-NLS-1$ //$NON-NLS-2$ - EXACT_MATCH("exactMatch", "http://www.w3.org/2004/02/skos/core#exactMatch"), //$NON-NLS-1$//$NON-NLS-2$ - BROAD_MATCH("broadMatch", "http://www.w3.org/2004/02/skos/core#broadMatch"), //$NON-NLS-1$//$NON-NLS-2$ - NARROW_MATCH("narrowMatch", "http://www.w3.org/2004/02/skos/core#narrowMatch"), //$NON-NLS-1$//$NON-NLS-2$ - RELATED_MATCH("relatedMatch", "http://www.w3.org/2004/02/skos/core#relatedMatch"), //$NON-NLS-1$//$NON-NLS-2$ - ALT_LABEL("altLabel", "http://www.w3.org/2004/02/skos/core#altLabel"), //$NON-NLS-1$ //$NON-NLS-2$ - TOP_MOST_CONCEPT("topMostConcept", "http://www.w3.org/2004/02/skos/core#hasTopConcept"), //$NON-NLS-1$ //$NON-NLS-2$ - LANGUAGE("languages", "http://purl.org/dc/elements/1.1/language"), //$NON-NLS-1$ //$NON-NLS-2$ - SORT_PRIORITY("sortPriority", "http://www.w3.org/ns/ui#sortPriority"); //$NON-NLS-1$ //$NON-NLS-2$ + BROADER(Builder.node("broader") //$NON-NLS-1$ + .label("has broader") //$NON-NLS-1$ + .uri("http://www.w3.org/2004/02/skos/core#broader")), //$NON-NLS-1$ + NARROWER(Builder.node("narrower") //$NON-NLS-1$ + .label("has narrower") //$NON-NLS-1$ + .uri("http://www.w3.org/2004/02/skos/core#narrower")), //$NON-NLS-1$ + RELATED(Builder.node("related") //$NON-NLS-1$ + .label("has related") //$NON-NLS-1$ + .uri("http://www.w3.org/2004/02/skos/core#related")), //$NON-NLS-1$ + PREF_LABEL(Builder.node("prefLabel") //$NON-NLS-1$ + .uri("http://www.w3.org/2004/02/skos/core#prefLabel")), //$NON-NLS-1$ + IN_SCHEME(Builder.node("schema") //$NON-NLS-1$ + .uri("http://www.w3.org/2004/02/skos/core#inScheme")), //$NON-NLS-1$ + CONCEPT(Builder.node("concept") //$NON-NLS-1$ + .uri("http://www.w3.org/2004/02/skos/core#Concept")), //$NON-NLS-1$ + CONCEPT_SCHEME(Builder.node("conceptScheme") //$NON-NLS-1$ + .uri("http://www.w3.org/2004/02/skos/core#ConceptScheme")), //$NON-NLS-1$ + RELATION(Builder.node("relation").uri("")), //$NON-NLS-1$ //$NON-NLS-2$ + LABEL(Builder.node("label") //$NON-NLS-1$ + .uri("http://www.w3.org/2000/01/rdf-schema#label")), //$NON-NLS-1$ + EXACT_MATCH(Builder.node("exactMatch") //$NON-NLS-1$ + .label("has exact match") //$NON-NLS-1$ + .uri("http://www.w3.org/2004/02/skos/core#exactMatch")), //$NON-NLS-1$ + CLOSE_MATCH(Builder.node("closeMatch") //$NON-NLS-1$ + .label("has close match") //$NON-NLS-1$ + .uri("http://www.w3.org/2004/02/skos/core#closeMatch")), //$NON-NLS-1$ + BROAD_MATCH(Builder.node("broadMatch") //$NON-NLS-1$ + .label("has broader match") //$NON-NLS-1$ + .uri("http://www.w3.org/2004/02/skos/core#broadMatch")), //$NON-NLS-1$ + NARROW_MATCH(Builder.node("narrowMatch") //$NON-NLS-1$ + .label("has narrower match") //$NON-NLS-1$ + .uri("http://www.w3.org/2004/02/skos/core#narrowMatch")), //$NON-NLS-1$ + RELATED_MATCH(Builder.node("relatedMatch") //$NON-NLS-1$ + .label("has related match") //$NON-NLS-1$ + .uri("http://www.w3.org/2004/02/skos/core#relatedMatch")), //$NON-NLS-1$ + ALT_LABEL(Builder.node("altLabel") //$NON-NLS-1$ + .uri("http://www.w3.org/2004/02/skos/core#altLabel")), //$NON-NLS-1$ + TOP_MOST_CONCEPT(Builder.node("topMostConcept") //$NON-NLS-1$ + .uri("http://www.w3.org/2004/02/skos/core#hasTopConcept")), //$NON-NLS-1$ + LANGUAGE(Builder.node("languages") //$NON-NLS-1$ + .uri("http://purl.org/dc/elements/1.1/language")), //$NON-NLS-1$ + SORT_PRIORITY(Builder.node("sortPriority") //$NON-NLS-1$ + .uri("http://www.w3.org/ns/ui#sortPriority")); //$NON-NLS-1$ + + private static class Builder { + private String name; + private String uri; + private String label; + + public static Builder node(String name) { + return new Builder(name); + } - private String label; + private Builder(String name) { + this.name = name; + } + + public Builder label(String label) { + this.label = label; + return this; + } + + public Builder uri(String uri) { + this.uri = uri; + return this; + } + } + + private String name; private String uri; + private String label; + + private SparqlNodes(Builder builder) { + this.name = builder.name; + this.label = builder.label; + this.uri = builder.uri; + } - private SparqlNodes(String label, String uri) { - this.label = label; - this.uri = uri; + public static SparqlNodes parseName(String name) { + for (SparqlNodes current : SparqlNodes.values()) { + if (current.getName().equals(name)) { + return current; + } + } + return null; } public static Collection getRelations() { @@ -62,26 +121,33 @@ public static List getRelationUris() { return labels; } - public String getLabel() { - if (isBlank(label)) { - throw new IllegalStateException("No Label specified for Node " + name()); //$NON-NLS-1$ + public String getName() { + if (isBlank(name)) { + throw new IllegalStateException("No name specified for Node " + name()); //$NON-NLS-1$ } - return label; + return name; } public String getUri() { if (isBlank(uri)) { - throw new IllegalStateException("No Uri specified for Node " + name()); //$NON-NLS-1$ + throw new IllegalStateException("No uri specified for Node " + name()); //$NON-NLS-1$ } return uri; } + public String getLabel() { + if (isBlank(label)) { + throw new IllegalStateException("No label specified for Node " + name()); //$NON-NLS-1$ + } + return label; + } + public Node createUriNode() { return NodeFactory.createURI(getUri()); } public Node createVariableNode() { - return NodeFactory.createVariable(getLabel()); + return NodeFactory.createVariable(getName()); } public boolean hasUri(String uri) { @@ -89,7 +155,7 @@ public boolean hasUri(String uri) { } public Var createVar() { - return Var.alloc(getLabel()); + return Var.alloc(getName()); } public NodeValueString createUriValueString() { @@ -101,7 +167,7 @@ public Expr createStringExprVar() { } public ExprVar createExprVar() { - return new ExprVar(getLabel()); + return new ExprVar(getName()); } public Expr createLangExprVar() { @@ -118,7 +184,7 @@ public static String getLabelForUri(String uri) { return current.getLabel(); } } - return StringUtils.EMPTY; + return null; } } diff --git a/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/sparql/query/SparqlQueryBuilder.java b/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/sparql/query/SparqlQueryBuilder.java index dc88de2..eb2479d 100644 --- a/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/sparql/query/SparqlQueryBuilder.java +++ b/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/sparql/query/SparqlQueryBuilder.java @@ -39,7 +39,7 @@ public SparqlQueryBuilder withBody(Element body) { } public SparqlQueryBuilder addResultVariable(SparqlNodes node) { - return addResultVariable(node.getLabel()); + return addResultVariable(node.getName()); } public SparqlQueryBuilder addResultVariable(Node node) { @@ -51,6 +51,13 @@ public SparqlQueryBuilder addResultVariable(String label) { return this; } + public SparqlQueryBuilder addResultVariable(String label, boolean condition) { + if (condition) { + getQuery().addResultVar(label); + } + return this; + } + public SparqlQueryBuilder addResultVariable(String alias, Expr expression) { getQuery().addResultVar(alias, expression); return this; diff --git a/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/sparql/result/CommonResult.java b/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/sparql/result/CommonResult.java index 38e9a1b..8863f2a 100644 --- a/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/sparql/result/CommonResult.java +++ b/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/sparql/result/CommonResult.java @@ -1,10 +1,14 @@ //Copyright (c) 2014 by Disy Informationssysteme GmbH package net.disy.eenvplus.tfes.modules.sparql.result; +import static org.apache.commons.lang3.StringUtils.abbreviate; +import static org.apache.commons.lang3.StringUtils.rightPad; import net.disy.eenvplus.tfes.core.api.response.IRelative; import net.disy.eenvplus.tfes.core.api.response.ISuggestion; import net.disy.eenvplus.tfes.core.api.response.ISynonym; +import org.apache.commons.lang3.StringUtils; + // NOT_PUBLISHED class CommonResult implements ISuggestion, ISynonym, IRelative { @@ -101,4 +105,76 @@ public String getRelationUri() { return relationUri; } + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + if (StringUtils.isNotBlank(getRelationLabel())) { + builder.append(rightPad(getRelationLabel(), 20)); + } + builder.append(abbreviate(getLabel(), 20)).append('@').append(rightPad(getLanguage(), 6)); + builder.append('<').append(getConceptUri()).append('>'); + return builder.toString(); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((conceptUri == null) ? 0 : conceptUri.hashCode()); + result = prime * result + ((label == null) ? 0 : label.hashCode()); + result = prime * result + ((language == null) ? 0 : language.hashCode()); + result = prime * result + ((relationLabel == null) ? 0 : relationLabel.hashCode()); + result = prime * result + ((relationUri == null) ? 0 : relationUri.hashCode()); + result = prime * result + ((sourceLabel == null) ? 0 : sourceLabel.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + CommonResult other = (CommonResult) obj; + if (conceptUri == null) { + if (other.conceptUri != null) + return false; + } + else if (!conceptUri.equals(other.conceptUri)) + return false; + if (label == null) { + if (other.label != null) + return false; + } + else if (!label.equals(other.label)) + return false; + if (language == null) { + if (other.language != null) + return false; + } + else if (!language.equals(other.language)) + return false; + if (relationLabel == null) { + if (other.relationLabel != null) + return false; + } + else if (!relationLabel.equals(other.relationLabel)) + return false; + if (relationUri == null) { + if (other.relationUri != null) + return false; + } + else if (!relationUri.equals(other.relationUri)) + return false; + if (sourceLabel == null) { + if (other.sourceLabel != null) + return false; + } + else if (!sourceLabel.equals(other.sourceLabel)) + return false; + return true; + } + } diff --git a/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/sparql/result/ISourceLabelProvider.java b/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/sparql/result/ISourceLabelProvider.java new file mode 100644 index 0000000..2babc56 --- /dev/null +++ b/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/sparql/result/ISourceLabelProvider.java @@ -0,0 +1,7 @@ +//Copyright (c) 2015 by Disy Informationssysteme GmbH +package net.disy.eenvplus.tfes.modules.sparql.result; + +// NOT_PUBLISHED +public interface ISourceLabelProvider { + String provideFor(String uri); +} diff --git a/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/sparql/result/QuerySolutionItemExtractors.java b/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/sparql/result/QuerySolutionItemExtractors.java index 9e5cd8a..c8482de 100644 --- a/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/sparql/result/QuerySolutionItemExtractors.java +++ b/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/sparql/result/QuerySolutionItemExtractors.java @@ -23,7 +23,7 @@ public static String getLabel(String key, QuerySolution querySolution) { } public static String getLabel(SparqlNodes node, QuerySolution querySolution) { - return getLabel(node.getLabel(), querySolution); + return getLabel(node.getName(), querySolution); } public static String getLanguage(String key, QuerySolution querySolution) { @@ -35,7 +35,7 @@ public static String getLanguage(String key, QuerySolution querySolution) { } public static String getLanguage(SparqlNodes node, QuerySolution querySolution) { - return getLanguage(node.getLabel(), querySolution); + return getLanguage(node.getName(), querySolution); } public static String getUri(String key, QuerySolution querySolution) { @@ -47,7 +47,7 @@ public static String getUri(String key, QuerySolution querySolution) { } public static String getUri(SparqlNodes node, QuerySolution querySolution) { - return getUri(node.getLabel(), querySolution); + return getUri(node.getName(), querySolution); } public static Double getDouble(String label, QuerySolution querySolution) { @@ -56,7 +56,7 @@ public static Double getDouble(String label, QuerySolution querySolution) { } public static Double getDouble(SparqlNodes node, QuerySolution querySolution) { - return getDouble(node.getLabel(), querySolution); + return getDouble(node.getName(), querySolution); } } diff --git a/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/sparql/result/ResultFactory.java b/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/sparql/result/ResultFactory.java index 2edc381..bdd246d 100644 --- a/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/sparql/result/ResultFactory.java +++ b/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/sparql/result/ResultFactory.java @@ -1,11 +1,15 @@ //Copyright (c) 2014 by Disy Informationssysteme GmbH package net.disy.eenvplus.tfes.modules.sparql.result; +import net.disy.eenvplus.tfes.core.api.response.IRelatedConcept; import net.disy.eenvplus.tfes.core.api.response.IRelative; import net.disy.eenvplus.tfes.core.api.response.ISuggestion; import net.disy.eenvplus.tfes.core.api.response.ISynonym; import net.disy.eenvplus.tfes.modules.sparql.query.SparqlNodes; +import org.apache.commons.lang3.StringUtils; + +import com.hp.hpl.jena.graph.Node; import com.hp.hpl.jena.query.QuerySolution; // NOT_PUBLISHED @@ -20,7 +24,7 @@ public static ISuggestion createSuggestion( final SparqlNodes label, final SparqlNodes uri, final String sourceLabel) { - return createSuggestion(current, label.getLabel(), uri.getLabel(), sourceLabel); + return createSuggestion(current, label.getName(), uri.getName(), sourceLabel); } public static ISuggestion createSuggestion( @@ -28,7 +32,7 @@ public static ISuggestion createSuggestion( final String label, final SparqlNodes uri, final String sourceLabel) { - return createSuggestion(current, label, uri.getLabel(), sourceLabel); + return createSuggestion(current, label, uri.getName(), sourceLabel); } public static ISuggestion createSuggestion( @@ -74,4 +78,25 @@ public static IRelative createRelative( .sourceLabel(QuerySolutionItemExtractors.getLabel(sourceLabel, current)) .build(); } + + public static IRelatedConcept createRelatedConcept( + QuerySolution current, + Node concept, + Node conceptLabel, + Node relation, + ISourceLabelProvider sourceLabel) { + String conceptUri = QuerySolutionItemExtractors.getUri(concept.getName(), current); + if (StringUtils.isBlank(conceptUri)) { + return null; + } + String relationUri = QuerySolutionItemExtractors.getUri(relation.getName(), current); + return new CommonResult.Builder() + .conceptUri(conceptUri) + .label(QuerySolutionItemExtractors.getLabel(conceptLabel.getName(), current)) + .language(QuerySolutionItemExtractors.getLanguage(conceptLabel.getName(), current)) + .relationUri(relationUri) + .relationLabel(SparqlNodes.getLabelForUri(relationUri)) + .sourceLabel(sourceLabel.provideFor(conceptUri)) + .build(); + } } diff --git a/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/topmost/TopMostConceptSparqlQueryBuilder.java b/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/topmost/TopMostConceptSparqlQueryBuilder.java index 2fba9ba..5c52a5a 100644 --- a/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/topmost/TopMostConceptSparqlQueryBuilder.java +++ b/TF_Exploitation_Server_modules/src/main/java/net/disy/eenvplus/tfes/modules/topmost/TopMostConceptSparqlQueryBuilder.java @@ -49,9 +49,9 @@ public static TopMostConceptSparqlQueryBuilder createQuery( @Override protected SparqlQueryBuilder adapt(SparqlQueryBuilder builder) { return builder - .addResultVariable(CONCEPT.getLabel()) + .addResultVariable(CONCEPT.getName()) .addResultVariable(schemeLabel) - .addResultVariable(TOP_MOST_CONCEPT.getLabel()) + .addResultVariable(TOP_MOST_CONCEPT.getName()) .addResultVariable(topMostConceptLabel); } diff --git a/TF_Exploitation_Server_modules/src/test/java/net/disy/eenvplus/tfes/modules/keyword/completion/KeywordCompletionModuleTest.java b/TF_Exploitation_Server_modules/src/test/java/net/disy/eenvplus/tfes/modules/keyword/completion/KeywordCompletionModuleTest.java index defa65c..e70ad7f 100644 --- a/TF_Exploitation_Server_modules/src/test/java/net/disy/eenvplus/tfes/modules/keyword/completion/KeywordCompletionModuleTest.java +++ b/TF_Exploitation_Server_modules/src/test/java/net/disy/eenvplus/tfes/modules/keyword/completion/KeywordCompletionModuleTest.java @@ -108,8 +108,8 @@ public void standardQueryInitialisation() throws Exception { jenaQuery.getValue(), hasToString(allOf( containsString(LONG_TEST_KEYWORD), - containsString(LABEL.getLabel()), - containsString(CONCEPT.getLabel())))); + containsString(LABEL.getName()), + containsString(CONCEPT.getName())))); assertResult(suggestions); } diff --git a/TF_Exploitation_Server_modules/src/test/java/net/disy/eenvplus/tfes/modules/keyword/completion/SuggestionSparqlQueryBuilderTest.java b/TF_Exploitation_Server_modules/src/test/java/net/disy/eenvplus/tfes/modules/keyword/completion/SuggestionSparqlQueryBuilderTest.java index c397057..a4db865 100644 --- a/TF_Exploitation_Server_modules/src/test/java/net/disy/eenvplus/tfes/modules/keyword/completion/SuggestionSparqlQueryBuilderTest.java +++ b/TF_Exploitation_Server_modules/src/test/java/net/disy/eenvplus/tfes/modules/keyword/completion/SuggestionSparqlQueryBuilderTest.java @@ -41,17 +41,17 @@ public void simpleQuery() { query, hasToString(both(startsWith("SELECT DISTINCT")).and( stringContainsInOrder(asList( - LABEL.getLabel(), - CONCEPT.getLabel(), + LABEL.getName(), + CONCEPT.getName(), "WHERE", - CONCEPT.getLabel(), + CONCEPT.getName(), PREF_LABEL.getUri(), - LABEL.getLabel(), - CONCEPT.getLabel(), + LABEL.getName(), + CONCEPT.getName(), ALT_LABEL.getUri(), - LABEL.getLabel(), + LABEL.getName(), "FILTER", - LABEL.getLabel(), + LABEL.getName(), TEST_KEYWORD))))); } @@ -110,7 +110,7 @@ public void sources() throws Exception { hasToString(both(startsWith("SELECT DISTINCT")).and( stringContainsInOrder(asList( "OPTIONAL", - IN_SCHEME.getLabel(), + IN_SCHEME.getName(), LABEL.getUri(), TEST_SOURCE))))); diff --git a/TF_Exploitation_Server_modules/src/test/java/net/disy/eenvplus/tfes/modules/keyword/explanation/KeywordExplanationModuleTest.java b/TF_Exploitation_Server_modules/src/test/java/net/disy/eenvplus/tfes/modules/keyword/explanation/KeywordExplanationModuleTest.java index 4ad7936..f096b04 100644 --- a/TF_Exploitation_Server_modules/src/test/java/net/disy/eenvplus/tfes/modules/keyword/explanation/KeywordExplanationModuleTest.java +++ b/TF_Exploitation_Server_modules/src/test/java/net/disy/eenvplus/tfes/modules/keyword/explanation/KeywordExplanationModuleTest.java @@ -96,7 +96,7 @@ public void standardQuery() throws InterruptedException, ExecutionException { hasToString(stringContainsInOrder(asList( LONG_TEST_CONCEPT, "AS", - CONCEPT.getLabel(), + CONCEPT.getName(), "?p", "?o", "WHERE", @@ -104,7 +104,7 @@ public void standardQuery() throws InterruptedException, ExecutionException { "?p", "?o", IN_SCHEME.getUri(), - IN_SCHEME.getLabel())))); + IN_SCHEME.getName())))); verify(resultSetMapper).map(any(ResultSet.class)); } diff --git a/TF_Exploitation_Server_modules/src/test/java/net/disy/eenvplus/tfes/modules/keyword/explanation/SimpleExplanationQueryBuilderTest.java b/TF_Exploitation_Server_modules/src/test/java/net/disy/eenvplus/tfes/modules/keyword/explanation/SimpleExplanationQueryBuilderTest.java index d7637e9..a02230d 100644 --- a/TF_Exploitation_Server_modules/src/test/java/net/disy/eenvplus/tfes/modules/keyword/explanation/SimpleExplanationQueryBuilderTest.java +++ b/TF_Exploitation_Server_modules/src/test/java/net/disy/eenvplus/tfes/modules/keyword/explanation/SimpleExplanationQueryBuilderTest.java @@ -42,7 +42,7 @@ public void simpleQuery() { assertThat(jenaQuery, hasToString(stringContainsInOrder(asList( "SELECT", "DISTINCT", // - TEST_CONCEPT, "AS", CONCEPT.getLabel(), "?p", "?o",// + TEST_CONCEPT, "AS", CONCEPT.getName(), "?p", "?o",// "WHERE", "{", // TEST_CONCEPT, "?p", "?o", // IN_SCHEME.getUri(), "?schema",// @@ -64,7 +64,7 @@ public void oneThesaurus() { assertThat( jenaQuery, - hasToString(stringContainsInOrder(asList("FILTER", IN_SCHEME.getLabel(), TEST_SCHEMA_1)))); + hasToString(stringContainsInOrder(asList("FILTER", IN_SCHEME.getName(), TEST_SCHEMA_1)))); } @Test @@ -76,8 +76,8 @@ public void twoThesauri() { assertThat( jenaQuery, hasToString(both( - stringContainsInOrder(asList("FILTER", IN_SCHEME.getLabel(), TEST_SCHEMA_1))) // - .and(stringContainsInOrder(asList("FILTER", IN_SCHEME.getLabel(), TEST_SCHEMA_2))))); + stringContainsInOrder(asList("FILTER", IN_SCHEME.getName(), TEST_SCHEMA_1))) // + .and(stringContainsInOrder(asList("FILTER", IN_SCHEME.getName(), TEST_SCHEMA_2))))); } @Test diff --git a/TF_Exploitation_Server_modules/src/test/java/net/disy/eenvplus/tfes/modules/semantic/neighbourhood/RelativeNeighbourhoodQueryBuilderTest.java b/TF_Exploitation_Server_modules/src/test/java/net/disy/eenvplus/tfes/modules/semantic/neighbourhood/RelativeNeighbourhoodQueryBuilderTest.java new file mode 100644 index 0000000..845ebb9 --- /dev/null +++ b/TF_Exploitation_Server_modules/src/test/java/net/disy/eenvplus/tfes/modules/semantic/neighbourhood/RelativeNeighbourhoodQueryBuilderTest.java @@ -0,0 +1,24 @@ +package net.disy.eenvplus.tfes.modules.semantic.neighbourhood; + +import java.util.Arrays; + +import org.junit.Test; + +import com.hp.hpl.jena.query.Query; + +@SuppressWarnings("nls") +public class RelativeNeighbourhoodQueryBuilderTest { + + @Test + public void printQuery() throws Exception { + Query query = RelativeNeighbourhoodQueryBuilder + .createRelativeNeighbourhoodQuery("http://www.eionet.europa.eu/gemet/concept/11433") + .withLanguages(Arrays.asList("en")) + // .withRelations(Arrays.asList("exactMatch", "related")) + .withDepth(3) + .build(); + + System.out.println("RelativeNeighbourhoodQueryBuilderTest.testname(): " + query); + } + +} diff --git a/TF_Exploitation_Server_modules/src/test/java/net/disy/eenvplus/tfes/modules/semantic/neighbourhood/RelativeNeighbourhoodResultTreeBuilderTest.java b/TF_Exploitation_Server_modules/src/test/java/net/disy/eenvplus/tfes/modules/semantic/neighbourhood/RelativeNeighbourhoodResultTreeBuilderTest.java new file mode 100644 index 0000000..3bbf737 --- /dev/null +++ b/TF_Exploitation_Server_modules/src/test/java/net/disy/eenvplus/tfes/modules/semantic/neighbourhood/RelativeNeighbourhoodResultTreeBuilderTest.java @@ -0,0 +1,175 @@ +package net.disy.eenvplus.tfes.modules.semantic.neighbourhood; + +import static java.util.Arrays.asList; +import static net.disy.eenvplus.tfes.core.api.response.ILabelledConceptMatcher.hasConceptUri; +import static net.disy.eenvplus.tfes.core.api.response.IRelatedConceptBuilder.forConceptUri; +import static net.disy.eenvplus.tfes.core.api.response.IVisualizationNodeMatcher.hasChildren; +import static net.disy.eenvplus.tfes.core.api.response.IVisualizationNodeMatcher.hasElement; +import static net.disy.eenvplus.tfes.modules.semantic.neighbourhood.RelativeNeighbourhoodResultTreeBuilder.empty; +import static org.hamcrest.Matchers.both; +import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.containsInAnyOrder; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.nullValue; +import static org.junit.Assert.assertThat; +import net.disy.eenvplus.tfes.core.api.response.ILabelledConceptMatcher; +import net.disy.eenvplus.tfes.core.api.response.IRelatedConcept; +import net.disy.eenvplus.tfes.core.api.response.IVisualizationNode; + +import org.hamcrest.Matcher; +import org.hamcrest.Matchers; +import org.junit.Test; + +@SuppressWarnings("nls") +public class RelativeNeighbourhoodResultTreeBuilderTest { + + private static final String PARENT_URI = "test.parent.uri"; + private static final String CHILD_URI = "test.child.uri"; + private static final String GRAND_CHILD_URI = "test.grandchild.uri"; + + @Test + public void emptyHasNoConceptOrChildren() throws Exception { + IVisualizationNode empty = empty().build(); + + assertThat(empty, both(hasElement(nullValue())).and(hasNoChildren())); + } + + private static Matcher hasNoChildren() { + return hasChildren(Matchers. emptyIterable()); + } + + @Test + public void addSingleConceptSetsRootElement() throws Exception { + IRelatedConcept concept = forConceptUri(PARENT_URI).build(); + IVisualizationNode root = empty().addConcepts(asList(concept)).build(); + + assertThat(root, both(hasElement(equalTo(concept))).and(hasNoChildren())); + } + + @Test + public void addSingleConceptSetsChildren() throws Exception { + IRelatedConcept parent = forConceptUri(PARENT_URI).build(); + IRelatedConcept child = forConceptUri(CHILD_URI).build(); + IVisualizationNode root = empty().addConcepts(asList(parent, child)).build(); + + assertThat(root.getChildren(), contains(both(hasElement(equalTo(child))).and(hasNoChildren()))); + } + + @Test + public void addSingleConceptSetsGrandChildren() throws Exception { + IRelatedConcept parent = forConceptUri(PARENT_URI).build(); + IRelatedConcept child = forConceptUri(CHILD_URI).build(); + IRelatedConcept grandChild = forConceptUri(CHILD_URI + "/grand").build(); + IRelatedConcept greatGrandChild = forConceptUri(CHILD_URI + "/great").build(); + IRelatedConcept prodigy = forConceptUri(CHILD_URI + "/prodigy").build(); + IVisualizationNode root = empty().addConcepts( + asList(parent, child, grandChild, greatGrandChild, prodigy)).build(); + + assertThat(root, both(hasElement(equalTo(parent))).and(hasChildren(contains(// + both(hasElement(equalTo(child))).and(hasChildren(contains(// + both(hasElement(equalTo(grandChild))).and(hasChildren(contains(// + both(hasElement(equalTo(greatGrandChild))).and(hasChildren(contains(// + both(hasElement(equalTo(prodigy))).and(hasNoChildren())))))))))))))); + } + + @Test + public void ignoresConceptsWithDifferentParent() throws Exception { + IRelatedConcept parent1 = forConceptUri(PARENT_URI + "/1").build(); + IRelatedConcept child1 = forConceptUri(CHILD_URI + "/1").build(); + IRelatedConcept parent2 = forConceptUri(PARENT_URI + "/2").build(); + IRelatedConcept child2 = forConceptUri(CHILD_URI + "/2").build(); + IVisualizationNode root = empty() + .addConcepts(asList(parent1, child1)) + .addConcepts(asList(parent2, child2)) + .build(); + + assertThat( + root, + both(hasElement(equalTo(parent1))).and( + hasChildren(contains(both(hasElement(equalTo(child1))).and(hasNoChildren()))))); + } + + @SuppressWarnings("unchecked") + @Test + public void addsConceptsWithSameParent() throws Exception { + IRelatedConcept parent = forConceptUri(PARENT_URI).build(); + IRelatedConcept child1 = forConceptUri(CHILD_URI + "/1").build(); + IRelatedConcept child2 = forConceptUri(CHILD_URI + "/2").build(); + IVisualizationNode root = empty() + .addConcepts(asList(parent, child1)) + .addConcepts(asList(parent, child2)) + .build(); + + assertThat( + root, + both(hasElement(equalTo(parent))).and( + hasChildren(containsInAnyOrder( + both(hasElement(equalTo(child1))).and(hasNoChildren()), + both(hasElement(equalTo(child2))).and(hasNoChildren()))))); + } + + @SuppressWarnings("unchecked") + @Test + public void addsConceptsWithEqualParent() throws Exception { + IRelatedConcept parent1 = forConceptUri(PARENT_URI).build(); + IRelatedConcept child1 = forConceptUri(CHILD_URI + "/1").build(); + IRelatedConcept parent2 = forConceptUri(PARENT_URI).build(); + IRelatedConcept child2 = forConceptUri(CHILD_URI + "/2").build(); + + IVisualizationNode root = empty() + .addConcepts(asList(parent1, child1)) + .addConcepts(asList(parent2, child2)) + .build(); + + assertThat( + root, + both(hasElement(hasConceptUri(equalTo(PARENT_URI)))).and( + hasChildren(containsInAnyOrder( + both(hasElement(hasConceptUri(equalTo(CHILD_URI + "/1")))).and(hasNoChildren()), + both(hasElement(hasConceptUri(equalTo(CHILD_URI + "/2")))).and(hasNoChildren()))))); + } + + @SuppressWarnings("unchecked") + @Test + public void addsConceptsWithEqualParentAndChild() throws Exception { + IRelatedConcept parent1 = forConceptUri(PARENT_URI).build(); + IRelatedConcept child1 = forConceptUri(CHILD_URI).build(); + IRelatedConcept grandchild1 = forConceptUri(GRAND_CHILD_URI + "/1").build(); + IRelatedConcept parent2 = forConceptUri(PARENT_URI).build(); + IRelatedConcept child2 = forConceptUri(CHILD_URI).build(); + IRelatedConcept grandchild2 = forConceptUri(GRAND_CHILD_URI + "/2").build(); + + IVisualizationNode root = empty() + .addConcepts(asList(parent1, child1, grandchild1)) + .addConcepts(asList(parent2, child2, grandchild2)) + .build(); + + assertThat( + root, + both(hasElement(hasConceptUri(equalTo(PARENT_URI)))).and( + hasChildren(contains(both( + hasElement(ILabelledConceptMatcher.hasConceptUri(equalTo(CHILD_URI)))).and( + hasChildren(containsInAnyOrder( + both(hasElement(hasConceptUri(equalTo(GRAND_CHILD_URI + "/1")))).and( + hasNoChildren()), + both(hasElement(hasConceptUri(equalTo(GRAND_CHILD_URI + "/2")))).and( + hasNoChildren())))))))); + } + + @Test + public void removesConceptsWithSameParentAndCompatibleLanguage() throws Exception { + IRelatedConcept parent = forConceptUri(PARENT_URI).build(); + IRelatedConcept child1 = forConceptUri(CHILD_URI).withLanguage("en").build(); + IRelatedConcept child2 = forConceptUri(CHILD_URI).withLanguage("en-us").build(); + IVisualizationNode root = empty() + .addConcepts(asList(parent, child1)) + .addConcepts(asList(parent, child2)) + .build(); + + assertThat( + root, + both(hasElement(equalTo(parent))).and( + hasChildren(contains(both(hasElement(equalTo(child1))).and(hasNoChildren()))))); + } + +} diff --git a/TF_Exploitation_Server_modules/src/test/java/net/disy/eenvplus/tfes/modules/topmost/TopMostConceptSparqlQueryBuilderTest.java b/TF_Exploitation_Server_modules/src/test/java/net/disy/eenvplus/tfes/modules/topmost/TopMostConceptSparqlQueryBuilderTest.java index 449639b..5de7447 100644 --- a/TF_Exploitation_Server_modules/src/test/java/net/disy/eenvplus/tfes/modules/topmost/TopMostConceptSparqlQueryBuilderTest.java +++ b/TF_Exploitation_Server_modules/src/test/java/net/disy/eenvplus/tfes/modules/topmost/TopMostConceptSparqlQueryBuilderTest.java @@ -30,18 +30,18 @@ public void emptyQuery() throws Exception { sparqlQuery, hasToString(stringContainsInOrder(asList( "SELECT DISTINCT", - CONCEPT.getLabel(), + CONCEPT.getName(), SCHEME_LABEL, - TOP_MOST_CONCEPT.getLabel(), + TOP_MOST_CONCEPT.getName(), TOP_MOST_CONCEPT_LABEL, "WHERE", - CONCEPT.getLabel(), + CONCEPT.getName(), LABEL.getUri(), SCHEME_LABEL, ";", TOP_MOST_CONCEPT.getUri(), - TOP_MOST_CONCEPT.getLabel(), - PREF_LABEL.getLabel(), + TOP_MOST_CONCEPT.getName(), + PREF_LABEL.getName(), TOP_MOST_CONCEPT_LABEL)))); } @@ -73,8 +73,8 @@ public void thesauri() throws Exception { assertThat( sparqlQuery, hasToString(allOf( - stringContainsInOrder(asList("FILTER", IN_SCHEME.getLabel(), "=", "dieser")), - stringContainsInOrder(asList("FILTER", IN_SCHEME.getLabel(), "=", "jener"))))); + stringContainsInOrder(asList("FILTER", IN_SCHEME.getName(), "=", "dieser")), + stringContainsInOrder(asList("FILTER", IN_SCHEME.getName(), "=", "jener"))))); } diff --git a/TF_Exploitation_Server_web/pom.xml b/TF_Exploitation_Server_web/pom.xml index 5f4dd12..dcde707 100644 --- a/TF_Exploitation_Server_web/pom.xml +++ b/TF_Exploitation_Server_web/pom.xml @@ -9,7 +9,7 @@ net.disy.eenvplus eenvplus-tf-exploitation-server-parent - 0.3.3-SNAPSHOT + 0.4.4-SNAPSHOT @@ -17,13 +17,13 @@ net.disy.eenvplus eenvplus-tf-exploitation-server-core - 0.3.3-SNAPSHOT + 0.4.4-SNAPSHOT net.disy.eenvplus eenvplus-tf-exploitation-server-core - 0.3.3-SNAPSHOT + 0.4.4-SNAPSHOT test-jar test @@ -31,7 +31,7 @@ net.disy.eenvplus eenvplus-tf-exploitation-server-modules - 0.3.3-SNAPSHOT + 0.4.4-SNAPSHOT diff --git a/TF_Exploitation_Server_web/src/main/java/net/disy/eenvplus/tfes/web/api/core/RestMethodParameters.java b/TF_Exploitation_Server_web/src/main/java/net/disy/eenvplus/tfes/web/api/core/RestMethodParameters.java index b9b2685..7aa9c28 100644 --- a/TF_Exploitation_Server_web/src/main/java/net/disy/eenvplus/tfes/web/api/core/RestMethodParameters.java +++ b/TF_Exploitation_Server_web/src/main/java/net/disy/eenvplus/tfes/web/api/core/RestMethodParameters.java @@ -3,7 +3,7 @@ // NOT_PUBLISHED @SuppressWarnings("nls") -public interface RestMethodParameters { +public final class RestMethodParameters { public static final String CONCEPT = "concept"; public static final String KEYWORD = "keyword"; public static final String MAX_COUNT = "maxCount"; @@ -13,4 +13,9 @@ public interface RestMethodParameters { public static final String CROSS_WALKING = "cross-walking"; public static final String EXTRA_PARAMS = "extraParams"; public static final String SOURCE = "source"; + public static final String DEPTH = "depth"; + public static final String RELATIONS = "relations"; + + private RestMethodParameters() { + }; } diff --git a/TF_Exploitation_Server_web/src/main/java/net/disy/eenvplus/tfes/web/api/visualization/VisualizationResponse.java b/TF_Exploitation_Server_web/src/main/java/net/disy/eenvplus/tfes/web/api/visualization/VisualizationResponse.java new file mode 100644 index 0000000..7b7bc6a --- /dev/null +++ b/TF_Exploitation_Server_web/src/main/java/net/disy/eenvplus/tfes/web/api/visualization/VisualizationResponse.java @@ -0,0 +1,22 @@ +//Copyright (c) 2015 by Disy Informationssysteme GmbH +package net.disy.eenvplus.tfes.web.api.visualization; + +import net.disy.eenvplus.tfes.core.api.response.IVisualizationNode; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonInclude.Include; + +// NOT_PUBLISHED +@JsonInclude(Include.NON_EMPTY) +public class VisualizationResponse { + + private IVisualizationNode root; + + public VisualizationResponse(IVisualizationNode root) { + this.root = root; + } + + public IVisualizationNode getRoot() { + return root; + } +} diff --git a/TF_Exploitation_Server_web/src/main/java/net/disy/eenvplus/tfes/web/endpoint/controller/VisualizationController.java b/TF_Exploitation_Server_web/src/main/java/net/disy/eenvplus/tfes/web/endpoint/controller/VisualizationController.java new file mode 100644 index 0000000..87c7d0d --- /dev/null +++ b/TF_Exploitation_Server_web/src/main/java/net/disy/eenvplus/tfes/web/endpoint/controller/VisualizationController.java @@ -0,0 +1,72 @@ +//Copyright (c) 2015 by Disy Informationssysteme GmbH +package net.disy.eenvplus.tfes.web.endpoint.controller; + +import static java.util.Arrays.asList; +import static net.disy.eenvplus.tfes.web.api.core.RestMethodParameters.CONCEPT; +import static net.disy.eenvplus.tfes.web.api.core.RestMethodParameters.DEPTH; +import static net.disy.eenvplus.tfes.web.api.core.RestMethodParameters.LANGUAGES; +import static net.disy.eenvplus.tfes.web.api.core.RestMethodParameters.RELATIONS; +import static net.disy.eenvplus.tfes.web.endpoint.query.ServiceQueryBuilder.createConceptQuery; +import static org.apache.commons.lang3.StringUtils.split; +import net.disy.eenvplus.tfes.core.api.exceptions.ServiceException; +import net.disy.eenvplus.tfes.core.api.exceptions.UnknownRelationException; +import net.disy.eenvplus.tfes.core.api.query.QueryParameterKeys; +import net.disy.eenvplus.tfes.core.api.response.IVisualizationNode; +import net.disy.eenvplus.tfes.core.api.service.IServiceManager; +import net.disy.eenvplus.tfes.web.api.exceptions.ErrorResponseCodes; +import net.disy.eenvplus.tfes.web.api.rest.RestApiErrorMessage; +import net.disy.eenvplus.tfes.web.api.visualization.VisualizationResponse; +import net.disy.eenvplus.tfes.web.endpoint.core.ErrorResponseFactory; +import net.disy.eenvplus.tfes.web.endpoint.query.ServiceQuery; +import net.disy.eenvplus.tfes.web.validation.api.IVisualizationQueryValidator; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +// NOT_PUBLISHED + +@RestController +@RequestMapping("/visualization") +public class VisualizationController { + + @Autowired + private IServiceManager manager; + + @Autowired + private IVisualizationQueryValidator validator; + + @RequestMapping(method = RequestMethod.GET, produces = "application/vnd.tfes.visualization.flare+json; version=1; charset=UTF-8") + public ResponseEntity getVisualization( + @RequestParam(value = CONCEPT) String concept, + @RequestParam(value = LANGUAGES, defaultValue = "") String languages, + @RequestParam(value = RELATIONS, defaultValue = "") String relations, + @RequestParam(value = DEPTH, defaultValue = "3") Integer depth) throws ServiceException { + + ServiceQuery query = createConceptQuery(concept) + .withLanguages(languages) + .withExtraParameters(QueryParameterKeys.QUERY_DEPTH.getKey(), depth) + .withExtraParameters(QueryParameterKeys.RELATIONS.getKey(), asList(split(relations, ','))) + .build(); + validator.validate(query); + + IVisualizationNode root = manager.getRelativeNeighbourhood(query); + VisualizationResponse response = new VisualizationResponse(root); + + return new ResponseEntity<>(response, HttpStatus.OK); + } + + @ExceptionHandler + public ResponseEntity handleIllegalQueryType( + UnknownRelationException exception) { + return ErrorResponseFactory.createResponse( + ErrorResponseCodes.UNKNOWN_VALUE, + "relation: " + exception.getRelation()); //$NON-NLS-1$ + } + +} diff --git a/TF_Exploitation_Server_web/src/main/java/net/disy/eenvplus/tfes/web/endpoint/core/ErrorResponseFactory.java b/TF_Exploitation_Server_web/src/main/java/net/disy/eenvplus/tfes/web/endpoint/core/ErrorResponseFactory.java new file mode 100644 index 0000000..fa8fc49 --- /dev/null +++ b/TF_Exploitation_Server_web/src/main/java/net/disy/eenvplus/tfes/web/endpoint/core/ErrorResponseFactory.java @@ -0,0 +1,50 @@ +//Copyright (c) 2015 by Disy Informationssysteme GmbH +package net.disy.eenvplus.tfes.web.endpoint.core; + +import net.disy.eenvplus.tfes.web.api.exceptions.ErrorResponseCodes; +import net.disy.eenvplus.tfes.web.api.exceptions.IErrorResponseCode; +import net.disy.eenvplus.tfes.web.api.rest.RestApiErrorMessage; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; + +// NOT_PUBLISHED +public final class ErrorResponseFactory { + + private ErrorResponseFactory() { + } + + public static ResponseEntity createResponse( + ErrorResponseCodes responseCode, + Object... arguments) { + RestApiErrorMessage message = ErrorResponseFactory.createErrorMessage(responseCode, arguments); + HttpStatus httpStatus = responseCode.getHttpStatus(); + return new ResponseEntity(message, httpStatus); + } + + public static RestApiErrorMessage createErrorMessage( + IErrorResponseCode responseCode, + Object... arguments) { + RestApiErrorMessage message = new RestApiErrorMessage(); + message.setCode(responseCode.getCode()); + message.setText(responseCode.createText(arguments)); + return message; + } + + static RestApiErrorMessage createErrorMessage(IllegalQueryArgumentException exception) { + IErrorResponseCode errorResponseCode = exception.getResponseCode(); + Object[] arguments = exception.getArguments(); + return createErrorMessage(errorResponseCode, arguments); + } + + static void appendExceptionMessage(RestApiErrorMessage message, Exception exception) { + if (StringUtils.isNotBlank(exception.getLocalizedMessage())) { + StringBuilder builder = new StringBuilder(message.getText()); + builder.append("\n"); //$NON-NLS-1$ + builder.append(exception.getLocalizedMessage()); + message.setText(builder.toString()); + } + } + +} diff --git a/TF_Exploitation_Server_web/src/main/java/net/disy/eenvplus/tfes/web/endpoint/core/GlobalControllerExceptionHandler.java b/TF_Exploitation_Server_web/src/main/java/net/disy/eenvplus/tfes/web/endpoint/core/GlobalControllerExceptionHandler.java index b337a70..856896d 100644 --- a/TF_Exploitation_Server_web/src/main/java/net/disy/eenvplus/tfes/web/endpoint/core/GlobalControllerExceptionHandler.java +++ b/TF_Exploitation_Server_web/src/main/java/net/disy/eenvplus/tfes/web/endpoint/core/GlobalControllerExceptionHandler.java @@ -3,6 +3,8 @@ import static net.disy.eenvplus.tfes.web.api.exceptions.ErrorResponseCodes.INTERNAL; import static net.disy.eenvplus.tfes.web.api.exceptions.ErrorResponseCodes.MISSING_PARAMETER; +import static net.disy.eenvplus.tfes.web.endpoint.core.ErrorResponseFactory.createErrorMessage; +import static net.disy.eenvplus.tfes.web.endpoint.core.ErrorResponseFactory.createResponse; import static org.slf4j.LoggerFactory.getLogger; import net.disy.eenvplus.tfes.core.api.exceptions.ForbiddenServiceException; import net.disy.eenvplus.tfes.core.api.exceptions.ServiceException; @@ -11,7 +13,6 @@ import net.disy.eenvplus.tfes.web.api.exceptions.IErrorResponseCode; import net.disy.eenvplus.tfes.web.api.rest.RestApiErrorMessage; -import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.springframework.beans.TypeMismatchException; import org.springframework.core.annotation.AnnotationUtils; @@ -36,23 +37,6 @@ public ResponseEntity handleServiceException( return createResponse(ErrorResponseCodes.LOST_CONNECTION_SPARQL); } - private ResponseEntity createResponse( - ErrorResponseCodes responseCode, - Object... arguments) { - RestApiErrorMessage message = createErrorMessage(responseCode, arguments); - HttpStatus httpStatus = responseCode.getHttpStatus(); - return new ResponseEntity(message, httpStatus); - } - - public static RestApiErrorMessage createErrorMessage( - IErrorResponseCode responseCode, - Object... arguments) { - RestApiErrorMessage message = new RestApiErrorMessage(); - message.setCode(responseCode.getCode()); - message.setText(responseCode.createText(arguments)); - return message; - } - @ExceptionHandler public ResponseEntity handleServiceException( ForbiddenServiceException exception) { @@ -78,7 +62,7 @@ public RestApiErrorMessage handleIllegalArgumentException(IllegalArgumentExcepti @ExceptionHandler public ResponseEntity handleIllegalQueryArgument( IllegalQueryArgumentException exception) { - RestApiErrorMessage message = createErrorMessage(exception); + RestApiErrorMessage message = ErrorResponseFactory.createErrorMessage(exception); HttpStatus httpStatus = getHttpStatus(exception); return new ResponseEntity(message, httpStatus); } @@ -88,16 +72,10 @@ private HttpStatus getHttpStatus(IllegalQueryArgumentException exception) { return responseCode.getHttpStatus(); } - private static RestApiErrorMessage createErrorMessage(IllegalQueryArgumentException exception) { - IErrorResponseCode errorResponseCode = exception.getResponseCode(); - Object[] arguments = exception.getArguments(); - return createErrorMessage(errorResponseCode, arguments); - } - @ExceptionHandler public ResponseEntity handleMissingKeyword( MissingServletRequestParameterException exception) { - RestApiErrorMessage message = createErrorMessage( + RestApiErrorMessage message = ErrorResponseFactory.createErrorMessage( MISSING_PARAMETER, exception.getParameterName()); return new ResponseEntity(message, MISSING_PARAMETER.getHttpStatus()); @@ -116,8 +94,8 @@ public ResponseEntity defaultErrorHandler(Exception excepti } LOGGER.error("Unexpected general exception: ", exception); //$NON-NLS-1$ - RestApiErrorMessage message = createErrorMessage(INTERNAL); - appendExceptionMessage(message, exception); + RestApiErrorMessage message = ErrorResponseFactory.createErrorMessage(INTERNAL); + ErrorResponseFactory.appendExceptionMessage(message, exception); return new ResponseEntity(message, HttpStatus.INTERNAL_SERVER_ERROR); } @@ -126,13 +104,4 @@ private boolean isHandledBySpring(Exception exception) { return AnnotationUtils.findAnnotation(exception.getClass(), ResponseStatus.class) != null; } - private void appendExceptionMessage(RestApiErrorMessage message, Exception exception) { - if (StringUtils.isNotBlank(exception.getLocalizedMessage())) { - StringBuilder builder = new StringBuilder(message.getText()); - builder.append("\n"); - builder.append(exception.getLocalizedMessage()); - message.setText(builder.toString()); - } - } - } diff --git a/TF_Exploitation_Server_web/src/main/java/net/disy/eenvplus/tfes/web/endpoint/query/ServiceQueryBuilder.java b/TF_Exploitation_Server_web/src/main/java/net/disy/eenvplus/tfes/web/endpoint/query/ServiceQueryBuilder.java index 7d51758..e209a5a 100644 --- a/TF_Exploitation_Server_web/src/main/java/net/disy/eenvplus/tfes/web/endpoint/query/ServiceQueryBuilder.java +++ b/TF_Exploitation_Server_web/src/main/java/net/disy/eenvplus/tfes/web/endpoint/query/ServiceQueryBuilder.java @@ -109,4 +109,9 @@ public ServiceQueryBuilder withSource(boolean active) { return this; } + public ServiceQueryBuilder withExtraParameters(String key, Object value) { + extraParameters.put(key, value); + return this; + } + } \ No newline at end of file diff --git a/TF_Exploitation_Server_web/src/main/java/net/disy/eenvplus/tfes/web/validation/api/IVisualizationQueryValidator.java b/TF_Exploitation_Server_web/src/main/java/net/disy/eenvplus/tfes/web/validation/api/IVisualizationQueryValidator.java new file mode 100644 index 0000000..21bff8b --- /dev/null +++ b/TF_Exploitation_Server_web/src/main/java/net/disy/eenvplus/tfes/web/validation/api/IVisualizationQueryValidator.java @@ -0,0 +1,10 @@ +//Copyright (c) 2015 by Disy Informationssysteme GmbH +package net.disy.eenvplus.tfes.web.validation.api; + +import net.disy.eenvplus.tfes.core.api.query.IConceptQuery; + +// NOT_PUBLISHED + +public interface IVisualizationQueryValidator extends IServiceQueryValidator { + +} diff --git a/TF_Exploitation_Server_web/src/main/java/net/disy/eenvplus/tfes/web/validation/impl/VisualizationQueryValidator.java b/TF_Exploitation_Server_web/src/main/java/net/disy/eenvplus/tfes/web/validation/impl/VisualizationQueryValidator.java new file mode 100644 index 0000000..03486a5 --- /dev/null +++ b/TF_Exploitation_Server_web/src/main/java/net/disy/eenvplus/tfes/web/validation/impl/VisualizationQueryValidator.java @@ -0,0 +1,23 @@ +//Copyright (c) 2015 by Disy Informationssysteme GmbH +package net.disy.eenvplus.tfes.web.validation.impl; + +import java.util.List; + +import net.disy.eenvplus.tfes.core.api.capabilities.ServiceModuleDescription; +import net.disy.eenvplus.tfes.core.api.query.IConceptQuery; +import net.disy.eenvplus.tfes.web.validation.api.IVisualizationQueryValidator; + +import org.springframework.stereotype.Component; + +// NOT_PUBLISHED +@Component +public class VisualizationQueryValidator extends AbstractConceptQueryValidator + implements + IVisualizationQueryValidator { + + @Override + protected List getServiceModules() { + return getServiceManager().getRelativeNeighbourhoodDescriptions(); + } + +} diff --git a/TF_Exploitation_Server_web/src/main/resources/config/service-modules.properties b/TF_Exploitation_Server_web/src/main/resources/config/service-modules.properties index 82cfb98..951bdfb 100644 --- a/TF_Exploitation_Server_web/src/main/resources/config/service-modules.properties +++ b/TF_Exploitation_Server_web/src/main/resources/config/service-modules.properties @@ -5,6 +5,7 @@ use.keyword.completion.cross-walking.module=true use.keyword.explanation.module=true use.semantic.explorative.search.module=true use.semantic.explorative.search.cross-walking.module=true +use.semantic.neighbourhood.module=true use.keyword.translation.module=true use.keyword.translation.cross-walking.module=true use.thesaurus.resolution.module=true diff --git a/TF_Exploitation_Server_web/src/main/resources/log4j.properties b/TF_Exploitation_Server_web/src/main/resources/log4j.properties index ac69862..b9b77db 100644 --- a/TF_Exploitation_Server_web/src/main/resources/log4j.properties +++ b/TF_Exploitation_Server_web/src/main/resources/log4j.properties @@ -11,15 +11,28 @@ log4j.appender.file.MaxBackupIndex=50 log4j.appender.file.layout=org.apache.log4j.PatternLayout log4j.appender.file.layout.ConversionPattern=%-d [%t] %-5p %c{2} (%M:%L) - %m%n -log4j.logger.net.disy.eenvplus.tfes=INFO, file +log4j.appender.sparql=org.apache.log4j.RollingFileAppender +log4j.appender.sparql.Append=true +log4j.appender.sparql.File=${catalina.base}/logs/tfes-sparql.log +log4j.appender.sparql.MaxFileSize=100MB +log4j.appender.sparql.MaxBackupIndex=50 + +log4j.appender.sparql.layout=org.apache.log4j.PatternLayout +log4j.appender.sparql.layout.ConversionPattern=%-d [%t] %-5p %c{2} (%M:%L) - %m%n + +log4j.logger.net.disy.eenvplus.tfes=DEBUG, file log4j.additivity.net.disy.eenvplus.tfes=false log4j.logger.net.disy.eenvplus.tfes.web.logging.RequestLogger=TRACE, file log4j.additivity.net.disy.eenvplus.tfes.web.logging.RequestLogger=false -log4j.logger.net.disy.eenvplus.tfes.modules.core.ThesaurusSparqlConnector=DEBUG, file +log4j.logger.net.disy.eenvplus.tfes.modules.core.ThesaurusSparqlConnector=DEBUG, sparql log4j.additivity.net.disy.eenvplus.tfes.modules.core.ThesaurusSparqlConnector=false +log4j.logger.net.disy.eenvplus.tfes.modules.semantic.neighbourhood.RelativeNeighbourhoodResultTreeBuilder= DEBUG, sparql +log4j.additivity.net.disy.eenvplus.tfes.modules.semantic.neighbourhood.RelativeNeighbourhoodResultTreeBuilder=false + + log4j.logger.org.apache.http=ERROR, file log4j.logger.org.apache.http.wire=FATAL, file log4j.logger.org.springframework=WARN, file diff --git a/TF_Exploitation_Server_web/src/main/webapp/WEB-INF/web.xml b/TF_Exploitation_Server_web/src/main/webapp/WEB-INF/web.xml index 1a508a6..1716543 100644 --- a/TF_Exploitation_Server_web/src/main/webapp/WEB-INF/web.xml +++ b/TF_Exploitation_Server_web/src/main/webapp/WEB-INF/web.xml @@ -1,7 +1,7 @@ - + xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"> diff --git a/TF_Exploitation_Server_web/src/test/java/net/disy/eenvplus/tfes/web/endpoint/controller/DescribeConceptControllerTest.java b/TF_Exploitation_Server_web/src/test/java/net/disy/eenvplus/tfes/web/endpoint/controller/DescribeConceptControllerTest.java index 8d10cf1..c8b7c8f 100644 --- a/TF_Exploitation_Server_web/src/test/java/net/disy/eenvplus/tfes/web/endpoint/controller/DescribeConceptControllerTest.java +++ b/TF_Exploitation_Server_web/src/test/java/net/disy/eenvplus/tfes/web/endpoint/controller/DescribeConceptControllerTest.java @@ -2,7 +2,7 @@ import static java.util.Arrays.asList; import static net.disy.eenvplus.tfes.core.api.capabilities.ParameterDescriptionMatcher.hasName; -import static net.disy.eenvplus.tfes.core.api.query.IConceptQueryMatcher.hasKeyword; +import static net.disy.eenvplus.tfes.core.api.query.IConceptQueryMatcher.hasConcept; import static net.disy.eenvplus.tfes.core.api.query.IServiceQueryMatcher.hasExtraParameters; import static net.disy.eenvplus.tfes.core.api.query.IServiceQueryMatcher.hasLanguages; import static net.disy.eenvplus.tfes.core.api.query.IServiceQueryMatcher.hasMaxCount; @@ -140,7 +140,7 @@ public void createsCorrectQuery() throws ServiceException { verify(serviceManager, times(1)).describeConcept(query.capture()); IConceptQuery delegatedQuery = query.getValue(); - assertThat(delegatedQuery, hasKeyword(equalTo(TEST_CONCEPT))); + assertThat(delegatedQuery, hasConcept(equalTo(TEST_CONCEPT))); assertThat(delegatedQuery, hasMaxCount(equalTo(TEST_MAX_COUNT))); @SuppressWarnings("unchecked") Matcher> testThesauri = containsInAnyOrder( diff --git a/TF_Exploitation_Server_web/src/test/java/net/disy/eenvplus/tfes/web/endpoint/controller/VisualizationControllerTest.java b/TF_Exploitation_Server_web/src/test/java/net/disy/eenvplus/tfes/web/endpoint/controller/VisualizationControllerTest.java new file mode 100644 index 0000000..f24774e --- /dev/null +++ b/TF_Exploitation_Server_web/src/test/java/net/disy/eenvplus/tfes/web/endpoint/controller/VisualizationControllerTest.java @@ -0,0 +1,75 @@ +package net.disy.eenvplus.tfes.web.endpoint.controller; + +import static net.disy.eenvplus.tfes.core.api.query.IConceptQueryMatcher.hasConcept; +import static net.disy.eenvplus.tfes.core.api.query.IServiceQueryMatcher.hasExtraParameters; +import static net.disy.eenvplus.tfes.core.api.query.IServiceQueryMatcher.hasLanguages; +import static org.hamcrest.Matchers.both; +import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.containsInAnyOrder; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertThat; +import static org.mockito.ArgumentCaptor.forClass; +import static org.mockito.Mockito.verify; +import net.disy.eenvplus.tfes.core.api.query.IConceptQuery; +import net.disy.eenvplus.tfes.core.api.query.IServiceQueryMatcher; +import net.disy.eenvplus.tfes.core.api.query.QueryParameterKeys; +import net.disy.eenvplus.tfes.core.api.service.IServiceManager; +import net.disy.eenvplus.tfes.web.validation.api.IVisualizationQueryValidator; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; + +@SuppressWarnings("nls") +@RunWith(MockitoJUnitRunner.class) +public class VisualizationControllerTest { + + @Rule + public ExpectedException thrown = ExpectedException.none(); + + @Mock + private IServiceManager manager; + + @Mock + private IVisualizationQueryValidator validator; + + @InjectMocks + private VisualizationController controller; + + @Test + public void createsCorrectQuery() throws Exception { + ArgumentCaptor queryCaptor = forClass(IConceptQuery.class); + + controller.getVisualization("concept", "lang1,lang2", "relation1,relation2", 3); + + verify(validator).validate(queryCaptor.capture()); + assertThat( + queryCaptor.getValue(), + both(hasConcept(equalTo("concept"))) + .and(hasLanguages(containsInAnyOrder("lang1", "lang2"))) + .and( + hasExtraParameters(QueryParameterKeys.RELATIONS, contains("relation1", "relation2"))) + .and( + IServiceQueryMatcher.hasExtraParameters(QueryParameterKeys.QUERY_DEPTH, equalTo(3)))); + } + + @Test + public void usesSameQueryforValidationAndService() throws Exception { + ArgumentCaptor validationQueryCaptor = forClass(IConceptQuery.class); + ArgumentCaptor serviceQueryCaptor = forClass(IConceptQuery.class); + + controller.getVisualization("concept", "lang1,lang2", "relation1,relation2", null); + + verify(validator).validate(validationQueryCaptor.capture()); + verify(manager).getRelativeNeighbourhood(serviceQueryCaptor.capture()); + + assertThat(validationQueryCaptor.getValue(), is(serviceQueryCaptor.getValue())); + } + +} diff --git a/TF_Exploitation_Server_web/src/test/java/net/disy/eenvplus/tfes/web/integration/GetRelativesIT.java b/TF_Exploitation_Server_web/src/test/java/net/disy/eenvplus/tfes/web/integration/GetRelativesIT.java index 06a5b2a..e05cfe9 100644 --- a/TF_Exploitation_Server_web/src/test/java/net/disy/eenvplus/tfes/web/integration/GetRelativesIT.java +++ b/TF_Exploitation_Server_web/src/test/java/net/disy/eenvplus/tfes/web/integration/GetRelativesIT.java @@ -68,14 +68,15 @@ public void relativesWithoutCrossWalking() throws Exception { .perform(getRelatives().param(CONCEPT, URI_CONCEPT_SOIL)) .andExpect(status().isOk()) .andExpect(content().contentType(CONTENT_TYPE)) - .andExpect(jsonPath("$relatives[*].relation.label", hasItems("broader", "narrower"))) + .andExpect( + jsonPath("$relatives[*].relation.label", hasItems("has broader", "has narrower"))) .andExpect( jsonPath( - "$relatives[?(@.relation.label=='broader')].keyword.title", + "$relatives[?(@.relation.label=='has broader')].keyword.title", hasItem("INSPIRE theme register"))) .andExpect( jsonPath( - "$relatives[?(@.relation.label=='narrower')].keyword.title", + "$relatives[?(@.relation.label=='has narrower')].keyword.title", hasItem("Derived Soil Profile"))); } @@ -89,7 +90,8 @@ public void relativesLanguagesWithoutCrossWalking() throws Exception { .perform(getRelatives().param(CONCEPT, URI_CONCEPT_REGULATIONS).param(LANGUAGES, "en,de")) .andExpect(status().isOk()) .andExpect(content().contentType(CONTENT_TYPE)) - .andExpect(jsonPath("$relatives[*].relation.label", hasItems("related", "narrower"))) + .andExpect( + jsonPath("$relatives[*].relation.label", hasItems("has related", "has narrower"))) .andExpect( jsonPath( "$relatives[*].keyword.language", @@ -109,7 +111,8 @@ public void relativesThesauriWithoutCrossWalking() throws Exception { "http://www.eionet.europa.eu/gemet/gemetThesaurus")) .andExpect(status().isOk()) .andExpect(content().contentType(CONTENT_TYPE)) - .andExpect(jsonPath("$relatives[*].relation.label", hasItems("related", "narrower"))) + .andExpect( + jsonPath("$relatives[*].relation.label", hasItems("has related", "has narrower"))) .andExpect( jsonPath( "$relatives[*].keyword.conceptUri", @@ -143,8 +146,8 @@ public void relativesCrossWalkingOnly() throws Exception { .andExpect( jsonPath( "$relatives[*].relation.label", - both(hasItems("broadMatch", "relatedMatch", "narrowMatch")).and( - not(hasItems("broader", "related", "narrower"))))); + both(hasItems("has broader match", "has related match", "has narrower match")).and( + not(hasItems("has broader", "has related", "has narrower"))))); } @Test diff --git a/pom.xml b/pom.xml index c4c0b85..6756dd1 100644 --- a/pom.xml +++ b/pom.xml @@ -21,7 +21,7 @@ false - 0.3.3-SNAPSHOT + 0.4.4-SNAPSHOT TF_Exploitation_Server_core