diff --git a/mica-core/src/main/java/org/obiba/mica/core/service/StudyTableSourceServiceRegistry.java b/mica-core/src/main/java/org/obiba/mica/core/service/StudyTableSourceServiceRegistry.java index dc816651ea..2fb3907308 100644 --- a/mica-core/src/main/java/org/obiba/mica/core/service/StudyTableSourceServiceRegistry.java +++ b/mica-core/src/main/java/org/obiba/mica/core/service/StudyTableSourceServiceRegistry.java @@ -84,7 +84,6 @@ private StudyTableSource makeStudyTableSourceInternal(StudyTableContext context, Optional serviceOptional = pluginsService.getStudyTableSourceServices().stream() .filter(service -> service.isFor(source)).findFirst(); if (serviceOptional.isPresent()) { - // TODO add a context to the study table source StudyTableSource tableSource = serviceOptional.get().makeSource(source); tableSource.setStudyTableContext(context); if (tableSource instanceof StudyTableFileSource) { diff --git a/mica-core/src/main/java/org/obiba/mica/core/source/ExcelTableSource.java b/mica-core/src/main/java/org/obiba/mica/core/source/ExcelTableSource.java index d64a2e165d..76e94e74fd 100644 --- a/mica-core/src/main/java/org/obiba/mica/core/source/ExcelTableSource.java +++ b/mica-core/src/main/java/org/obiba/mica/core/source/ExcelTableSource.java @@ -29,7 +29,6 @@ public class ExcelTableSource extends AbstractStudyTableSource implements StudyT @NotNull private String path; - @NotNull private String table; private boolean initialized; @@ -73,22 +72,12 @@ public String getTable() { @Override public ValueTable getValueTable() { - ensureInitialzed(); + ensureInitialized(); return Strings.isNullOrEmpty(table) ? excelDatasource.getValueTables().stream().findFirst().get() : excelDatasource.getValueTable(table); } - @Override - public Mica.DatasetVariableContingencyDto getContingency(IVariable variable, IVariable crossVariable) { - throw new UnsupportedOperationException("Contingency search not available from an Excel file"); - } - - @Override - public Mica.DatasetVariableAggregationDto getVariableSummary(String variableName) { - throw new UnsupportedOperationException("Summary statistics not available from an Excel file"); - } - @Override public String getURN() { return Strings.isNullOrEmpty(table) ? String.format("urn:file:%s", path) : String.format("urn:file:%s:%s", path, table); @@ -99,7 +88,7 @@ public void initialise(InputStream in) { excelDatasource = new ExcelDatasource(path, in); } - private void ensureInitialzed() { + private void ensureInitialized() { if (!initialized) { Initialisables.initialise(excelDatasource); initialized = true; diff --git a/mica-core/src/main/java/org/obiba/mica/core/source/OpalTableSource.java b/mica-core/src/main/java/org/obiba/mica/core/source/OpalTableSource.java index e2a64ca932..7c740ead43 100644 --- a/mica-core/src/main/java/org/obiba/mica/core/source/OpalTableSource.java +++ b/mica-core/src/main/java/org/obiba/mica/core/source/OpalTableSource.java @@ -62,6 +62,11 @@ public ValueTable getValueTable() { return getDatasource().getValueTable(table); } + @Override + public boolean providesContingency() { + return true; + } + @Override public Mica.DatasetVariableContingencyDto getContingency(IVariable variable, IVariable crossVariable) { Search.QueryTermsDto query = QueryTermsUtil.getContingencyQuery(variable, crossVariable); @@ -69,6 +74,11 @@ public Mica.DatasetVariableContingencyDto getContingency(IVariable variable, IVa return OpalDtos.asDto(variable, crossVariable, getContext().getPrivacyThreshold(), results); } + @Override + public boolean providesVariableSummary() { + return true; + } + @Override public Mica.DatasetVariableAggregationDto getVariableSummary(String variableName) { RestValueTable.RestVariableValueSource variableValueSource = (RestValueTable.RestVariableValueSource) getRestValueTable().getVariableValueSource(variableName); diff --git a/mica-core/src/main/java/org/obiba/mica/dataset/service/CollectedDatasetService.java b/mica-core/src/main/java/org/obiba/mica/dataset/service/CollectedDatasetService.java index 91d69adb54..52956a9419 100644 --- a/mica-core/src/main/java/org/obiba/mica/dataset/service/CollectedDatasetService.java +++ b/mica-core/src/main/java/org/obiba/mica/dataset/service/CollectedDatasetService.java @@ -40,6 +40,7 @@ import org.obiba.mica.micaConfig.service.MicaConfigService; import org.obiba.mica.micaConfig.service.OpalService; import org.obiba.mica.network.service.NetworkService; +import org.obiba.mica.spi.source.StudyTableSource; import org.obiba.mica.study.NoSuchStudyException; import org.obiba.mica.study.domain.BaseStudy; import org.obiba.mica.study.domain.DataCollectionEvent; @@ -429,12 +430,15 @@ public DatasetVariable getDatasetVariable(StudyDataset dataset, String variableN @Cacheable(value = "dataset-variables", cacheResolver = "datasetVariablesCacheResolver", key = "#variableName") public Mica.DatasetVariableAggregationDto getVariableSummary(@NotNull StudyDataset dataset, String variableName) { log.info("Caching variable summary {} {}", dataset.getId(), variableName); - return getStudyTableSource(dataset, dataset.getSafeStudyTable()).getVariableSummary(variableName); + StudyTableSource tableSource = getStudyTableSource(dataset, dataset.getSafeStudyTable()); + return tableSource.providesVariableSummary() ? tableSource.getVariableSummary(variableName) : null; } public Mica.DatasetVariableContingencyDto getContingencyTable(@NotNull StudyDataset dataset, DatasetVariable variable, DatasetVariable crossVariable) throws NoSuchValueTableException, NoSuchVariableException { - return getStudyTableSource(dataset, dataset.getSafeStudyTable()).getContingency(variable, crossVariable); + + StudyTableSource tableSource = getStudyTableSource(dataset, dataset.getSafeStudyTable()); + return tableSource.providesContingency() ? tableSource.getContingency(variable, crossVariable) : null; } public void delete(String id) { diff --git a/mica-core/src/main/java/org/obiba/mica/dataset/service/HarmonizedDatasetService.java b/mica-core/src/main/java/org/obiba/mica/dataset/service/HarmonizedDatasetService.java index d203715435..d73823773b 100644 --- a/mica-core/src/main/java/org/obiba/mica/dataset/service/HarmonizedDatasetService.java +++ b/mica-core/src/main/java/org/obiba/mica/dataset/service/HarmonizedDatasetService.java @@ -36,6 +36,7 @@ import org.obiba.mica.micaConfig.service.MicaConfigService; import org.obiba.mica.micaConfig.service.OpalService; import org.obiba.mica.network.service.NetworkService; +import org.obiba.mica.spi.source.StudyTableSource; import org.obiba.mica.study.NoSuchStudyException; import org.obiba.mica.study.domain.BaseStudy; import org.obiba.mica.study.domain.HarmonizationStudy; @@ -380,8 +381,9 @@ public DatasetVariable getDatasetVariable(HarmonizationDataset dataset, String v public Mica.DatasetVariableAggregationDto getVariableSummary(@NotNull HarmonizationDataset dataset, String variableName, String studyId, String source) { for(BaseStudyTable baseTable : dataset.getBaseStudyTables()) { if(baseTable.isFor(studyId, source)) { - log.info("Caching variable summary {} {} {} {} {}", dataset.getId(), variableName, studyId, source); - return getStudyTableSource(dataset, baseTable).getVariableSummary(variableName); + log.info("Caching variable summary {} {} {} {}", dataset.getId(), variableName, studyId, source); + StudyTableSource tableSource = getStudyTableSource(dataset, baseTable); + return tableSource.providesVariableSummary() ? tableSource.getVariableSummary(variableName) : null; } } @@ -390,7 +392,8 @@ public Mica.DatasetVariableAggregationDto getVariableSummary(@NotNull Harmonizat public Mica.DatasetVariableContingencyDto getContingencyTable(@NotNull HarmonizationDataset dataset, @NotNull BaseStudyTable studyTable, DatasetVariable variable, DatasetVariable crossVariable) throws NoSuchStudyException, NoSuchValueTableException { - return getStudyTableSource(dataset, studyTable).getContingency(variable, crossVariable); + StudyTableSource tableSource = getStudyTableSource(dataset, studyTable); + return tableSource.providesContingency() ? tableSource.getContingency(variable, crossVariable) : null; } @Override diff --git a/mica-core/src/main/java/org/obiba/mica/micaConfig/service/PluginsService.java b/mica-core/src/main/java/org/obiba/mica/micaConfig/service/PluginsService.java index cb734f1605..c3b797f4f2 100644 --- a/mica-core/src/main/java/org/obiba/mica/micaConfig/service/PluginsService.java +++ b/mica-core/src/main/java/org/obiba/mica/micaConfig/service/PluginsService.java @@ -118,16 +118,16 @@ public void init() { */ private void initPlugins() { Collection plugins = getPlugins(true); - String pluginName = environment.getProperty(MICA_SEARCH_PLUGIN_NAME, DEFAULT_MICA_SEARCH_PLUGIN_NAME); + String searchPluginName = environment.getProperty(MICA_SEARCH_PLUGIN_NAME, DEFAULT_MICA_SEARCH_PLUGIN_NAME); try { - String pluginLatestVersion = getPluginRepositoryCache().getPluginLatestVersion(pluginName); + String pluginLatestVersion = getPluginRepositoryCache().getPluginLatestVersion(searchPluginName); // ensure there is a mica-search plugin installed if (plugins.stream().noneMatch(p -> "mica-search".equals(p.getType())) || plugins.stream() - .filter(plugin -> pluginName.equals(plugin.getName())) + .filter(plugin -> searchPluginName.equals(plugin.getName())) .filter(plugin -> plugin.getVersion().compareTo(new Version(pluginLatestVersion)) >= 0).count() == 0) { - installPlugin(pluginName, null); + installPlugin(searchPluginName, null); // rescan plugins plugins = getPlugins(true); } @@ -137,7 +137,7 @@ private void initPlugins() { boolean micaSearchFound = false; // mica-search plugin is a singleton List filteredPlugins = - plugins.stream().filter(plugin -> pluginName.equals(plugin.getName())) + plugins.stream().filter(plugin -> searchPluginName.equals(plugin.getName()) || "mica-source".equals(plugin.getType())) .sorted(Comparator.comparing(PluginResources::getVersion)) .collect(Collectors.toList()); @@ -145,6 +145,8 @@ private void initPlugins() { if ("mica-search".equals(plugin.getType()) && !micaSearchFound) { initSearchEngineServicePlugin(plugin); micaSearchFound = true; + } else if ("mica-source".equals(plugin.getType())) { + initStudyTableSourceServicePlugin(plugin); } } } @@ -162,8 +164,12 @@ private void initSearchEngineServicePlugin(PluginResources plugin) { servicePlugins.add(service); } - private void initStudyTableSourceServicePlugins(PluginResources plugin) { + private void initStudyTableSourceServicePlugin(PluginResources plugin) { StudyTableSourceServiceLoader.get(plugin.getURLClassLoader(false)).forEach(service -> { + Properties properties = plugin.getProperties(); + properties.setProperty("MICA_HOME", properties.getProperty("OPAL_HOME")); + properties.remove("OPAL_HOME"); + service.configure(properties); service.start(); servicePlugins.add(service); }); diff --git a/mica-rest/src/main/java/org/obiba/mica/dataset/rest/DatasourceNotAvailableExceptionMapper.java b/mica-rest/src/main/java/org/obiba/mica/dataset/rest/DatasourceNotAvailableExceptionMapper.java index fea8745cd4..7e7eec0e01 100644 --- a/mica-rest/src/main/java/org/obiba/mica/dataset/rest/DatasourceNotAvailableExceptionMapper.java +++ b/mica-rest/src/main/java/org/obiba/mica/dataset/rest/DatasourceNotAvailableExceptionMapper.java @@ -21,6 +21,6 @@ public class DatasourceNotAvailableExceptionMapper implements ExceptionMapper { @Override public Response toResponse(DatasourceNotAvailableException e) { - return Response.status(Status.SERVICE_UNAVAILABLE).entity("Verify the datasource is available.").build(); + return Response.status(Status.SERVICE_UNAVAILABLE).entity("Verify the datasource is available. " + e.getMessage()).build(); } } diff --git a/mica-spi/src/main/java/org/obiba/mica/spi/source/AbstractStudyTableSource.java b/mica-spi/src/main/java/org/obiba/mica/spi/source/AbstractStudyTableSource.java index 20bdbfb0f8..ffcb50df13 100644 --- a/mica-spi/src/main/java/org/obiba/mica/spi/source/AbstractStudyTableSource.java +++ b/mica-spi/src/main/java/org/obiba/mica/spi/source/AbstractStudyTableSource.java @@ -10,6 +10,8 @@ package org.obiba.mica.spi.source; +import org.obiba.mica.web.model.Mica; + /** * Helper class for implementing {@link StudyTableSource}. */ @@ -26,4 +28,23 @@ protected StudyTableContext getContext() { return context; } + @Override + public boolean providesContingency() { + return false; + } + + @Override + public Mica.DatasetVariableContingencyDto getContingency(IVariable variable, IVariable crossVariable) { + throw new UnsupportedOperationException("Contingency search not provided by: " + getClass().getSimpleName()); + } + + @Override + public boolean providesVariableSummary() { + return false; + } + + @Override + public Mica.DatasetVariableAggregationDto getVariableSummary(String variableName) { + throw new UnsupportedOperationException("Summary statistics not provided by: " + getClass().getSimpleName()); + } } diff --git a/mica-spi/src/main/java/org/obiba/mica/spi/source/AbstractStudyTableSourceService.java b/mica-spi/src/main/java/org/obiba/mica/spi/source/AbstractStudyTableSourceService.java new file mode 100644 index 0000000000..d28260528e --- /dev/null +++ b/mica-spi/src/main/java/org/obiba/mica/spi/source/AbstractStudyTableSourceService.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2022 OBiBa. All rights reserved. + * + * This program and the accompanying materials + * are made available under the terms of the GNU Public License v3.0. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.obiba.mica.spi.source; + +import java.util.Properties; + +/** + * Helper class. + */ +public abstract class AbstractStudyTableSourceService implements StudyTableSourceService { + + protected Properties properties; + + protected boolean running; + + @Override + public Properties getProperties() { + return properties; + } + + @Override + public void configure(Properties properties) { + this.properties = properties; + } + + @Override + public boolean isRunning() { + return running; + } + + @Override + public void start() { + this.running = true; + } + + @Override + public void stop() { + this.running = false; + } +} diff --git a/mica-spi/src/main/java/org/obiba/mica/spi/source/StudyTableSource.java b/mica-spi/src/main/java/org/obiba/mica/spi/source/StudyTableSource.java index b386a9e120..e02bf60f30 100644 --- a/mica-spi/src/main/java/org/obiba/mica/spi/source/StudyTableSource.java +++ b/mica-spi/src/main/java/org/obiba/mica/spi/source/StudyTableSource.java @@ -33,6 +33,13 @@ public interface StudyTableSource { */ ValueTable getValueTable(); + /** + * Whether crossing variables is supported. + * + * @return + */ + boolean providesContingency(); + /** * Make a contingency query and return results. * @@ -42,6 +49,13 @@ public interface StudyTableSource { */ Mica.DatasetVariableContingencyDto getContingency(IVariable variable, IVariable crossVariable); + /** + * Whether variable summaries are supported. + * + * @return + */ + boolean providesVariableSummary(); + /** * Get a variable summary statistics. * @@ -57,6 +71,11 @@ public interface StudyTableSource { */ String getURN(); + /** + * Set context in which the study table is defined. + * + * @param context + */ void setStudyTableContext(StudyTableContext context); } diff --git a/mica-spi/src/main/java/org/obiba/mica/spi/source/StudyTableSourceService.java b/mica-spi/src/main/java/org/obiba/mica/spi/source/StudyTableSourceService.java index 94727b4659..c28b2b008d 100644 --- a/mica-spi/src/main/java/org/obiba/mica/spi/source/StudyTableSourceService.java +++ b/mica-spi/src/main/java/org/obiba/mica/spi/source/StudyTableSourceService.java @@ -17,8 +17,19 @@ */ public interface StudyTableSourceService extends ServicePlugin { + /** + * Whether this service plugin can handle the study table source's URN. + * @param source + * @return + */ boolean isFor(String source); + /** + * Make a {@link StudyTableSource} from the source URN. + * + * @param source + * @return + */ StudyTableSource makeSource(String source); }