Skip to content

Commit

Permalink
[kbss-cvut/termit-ui#449] Resolve vocabulary importer based on provid…
Browse files Browse the repository at this point in the history
…ed media type.
  • Loading branch information
ledsoft committed Jul 25, 2024
1 parent dc3bace commit bf234d7
Show file tree
Hide file tree
Showing 10 changed files with 226 additions and 35 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import cz.cvut.kbss.termit.service.importer.VocabularyImporter;
import cz.cvut.kbss.termit.util.Configuration;
import cz.cvut.kbss.termit.util.Utils;
import jakarta.validation.constraints.NotNull;
import org.eclipse.rdf4j.model.IRI;
import org.eclipse.rdf4j.model.Literal;
import org.eclipse.rdf4j.model.Model;
Expand Down Expand Up @@ -361,4 +362,14 @@ private void handleGlossaryStringProperty(IRI property, Consumer<MultilingualStr
private void setVocabularyDescriptionFromGlossary(final Vocabulary vocabulary) {
handleGlossaryStringProperty(DCTERMS.DESCRIPTION, vocabulary::setDescription);
}

/**
* Checks whether this importer supports the specified media type.
*
* @param mediaType Media type to check
* @return {@code true} when media type is supported, {@code false} otherwise
*/
public static boolean supportsMediaType(@NotNull String mediaType) {
return Rio.getParserFormatForMIMEType(mediaType).isPresent();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package cz.cvut.kbss.termit.service.importer;

import cz.cvut.kbss.termit.model.Vocabulary;
import cz.cvut.kbss.termit.util.Constants;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.lang.NonNull;
import org.springframework.stereotype.Component;

@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class ExcelImporter implements VocabularyImporter {

/**
* Media type for legacy .xls files.
*/
private static final String XLS_MEDIA_TYPE = "application/vnd.ms-excel";

@Override
public Vocabulary importVocabulary(ImportConfiguration config, ImportInput data) {
// TODO
return null;
}

/**
* Checks whether this importer supports the specified media type.
*
* @param mediaType Media type to check
* @return {@code true} when media type is supported, {@code false} otherwise
*/
public static boolean supportsMediaType(@NonNull String mediaType) {
return Constants.MediaType.EXCEL.equals(mediaType) || XLS_MEDIA_TYPE.equals(mediaType);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import cz.cvut.kbss.termit.exception.importing.VocabularyExistsException;
import cz.cvut.kbss.termit.model.Vocabulary;
import jakarta.validation.constraints.NotNull;

import java.io.InputStream;
import java.net.URI;
Expand All @@ -25,7 +26,7 @@ public interface VocabularyImporter {
* @throws IllegalArgumentException Indicates invalid input data, e.g., no input streams, missing language tags
* etc.
*/
Vocabulary importVocabulary(ImportConfiguration config, ImportInput data);
Vocabulary importVocabulary(@NotNull ImportConfiguration config, @NotNull ImportInput data);

/**
* Vocabulary import configuration.
Expand All @@ -37,7 +38,7 @@ public interface VocabularyImporter {
* @param prePersist Procedure to call before persisting the resulting vocabulary
*/
record ImportConfiguration(boolean allowReIdentify, URI vocabularyIri,
Consumer<Vocabulary> prePersist) {
@NotNull Consumer<Vocabulary> prePersist) {
}

/**
Expand All @@ -46,6 +47,6 @@ record ImportConfiguration(boolean allowReIdentify, URI vocabularyIri,
* @param mediaType Media type of the imported data
* @param data Streams containing the data
*/
record ImportInput(String mediaType, InputStream... data) {
record ImportInput(@NotNull String mediaType, InputStream... data) {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package cz.cvut.kbss.termit.service.importer;

import cz.cvut.kbss.termit.exception.importing.UnsupportedImportMediaTypeException;
import cz.cvut.kbss.termit.model.Vocabulary;
import cz.cvut.kbss.termit.persistence.dao.skos.SKOSImporter;
import org.springframework.context.ApplicationContext;
import org.springframework.lang.NonNull;
import org.springframework.stereotype.Component;

/**
* Ensures correct importer is invoked for provided media types.
*/
@Component
public class VocabularyImporters implements VocabularyImporter {

private final ApplicationContext appContext;

public VocabularyImporters(ApplicationContext appContext) {
this.appContext = appContext;
}

@Override
public Vocabulary importVocabulary(@NonNull ImportConfiguration config, @NonNull ImportInput data) {
if (SKOSImporter.supportsMediaType(data.mediaType())) {
return getSkosImporter().importVocabulary(config, data);
}
if (ExcelImporter.supportsMediaType(data.mediaType())) {
return getExcelImporter().importVocabulary(config, data);
}
throw new UnsupportedImportMediaTypeException(
"Unsupported media type '" + data.mediaType() + "' for vocabulary import.");
}

private VocabularyImporter getSkosImporter() {
return appContext.getBean(SKOSImporter.class);
}

private VocabularyImporter getExcelImporter() {
return appContext.getBean(ExcelImporter.class);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,10 @@
import cz.cvut.kbss.termit.model.validation.ValidationResult;
import cz.cvut.kbss.termit.persistence.dao.BaseAssetDao;
import cz.cvut.kbss.termit.persistence.dao.VocabularyDao;
import cz.cvut.kbss.termit.persistence.dao.skos.SKOSImporter;
import cz.cvut.kbss.termit.service.IdentifierResolver;
import cz.cvut.kbss.termit.service.MessageFormatter;
import cz.cvut.kbss.termit.service.importer.VocabularyImporter;
import cz.cvut.kbss.termit.service.importer.VocabularyImporters;
import cz.cvut.kbss.termit.service.snapshot.SnapshotProvider;
import cz.cvut.kbss.termit.util.Configuration;
import cz.cvut.kbss.termit.util.Constants;
Expand All @@ -50,7 +50,6 @@
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.context.ApplicationContext;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
Expand Down Expand Up @@ -78,31 +77,23 @@ public class VocabularyRepositoryService extends BaseAssetRepositoryService<Voca

private final Configuration config;

private final ApplicationContext context;
private final VocabularyImporters importers;

private final DtoMapper dtoMapper;

@Autowired
public VocabularyRepositoryService(ApplicationContext context, VocabularyDao vocabularyDao,
IdentifierResolver idResolver,
public VocabularyRepositoryService(VocabularyDao vocabularyDao, IdentifierResolver idResolver,
Validator validator, EditableVocabularies editableVocabularies,
Configuration config, DtoMapper dtoMapper) {
Configuration config, VocabularyImporters importers, DtoMapper dtoMapper) {
super(validator);
this.context = context;
this.vocabularyDao = vocabularyDao;
this.idResolver = idResolver;
this.editableVocabularies = editableVocabularies;
this.config = config;
this.importers = importers;
this.dtoMapper = dtoMapper;
}

/**
* This method ensures new instances of the prototype-scoped bean are returned on every call.
*/
private SKOSImporter getSKOSImporter() {
return context.getBean(SKOSImporter.class);
}

@Override
protected BaseAssetDao<Vocabulary> getPrimaryDao() {
return vocabularyDao;
Expand Down Expand Up @@ -231,7 +222,7 @@ public Vocabulary importVocabulary(boolean rename, MultipartFile file) {
Objects.requireNonNull(file);
try {
String contentType = resolveContentType(file);
return getSKOSImporter().importVocabulary(
return importers.importVocabulary(
new VocabularyImporter.ImportConfiguration(rename, null, this::initDocument),
new VocabularyImporter.ImportInput(contentType, file.getInputStream()));
} catch (VocabularyImportException e) {
Expand All @@ -254,7 +245,7 @@ public Vocabulary importVocabulary(URI vocabularyIri, MultipartFile file) {
Objects.requireNonNull(file);
try {
String contentType = resolveContentType(file);
return getSKOSImporter().importVocabulary(
return importers.importVocabulary(
new VocabularyImporter.ImportConfiguration(false, vocabularyIri, this::initDocument),
new VocabularyImporter.ImportInput(contentType, file.getInputStream()));
} catch (VocabularyImportException e) {
Expand Down
3 changes: 3 additions & 0 deletions src/main/java/cz/cvut/kbss/termit/util/Constants.java
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,9 @@ private RDFa() {
* Additional media types not covered by {@link org.springframework.http.MediaType}.
*/
public static final class MediaType {
/**
* Media type for .xlsx
*/
public static final String EXCEL = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
public static final String TURTLE = "text/turtle";
public static final String RDF_XML = "application/rdf+xml";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@
import org.eclipse.rdf4j.repository.RepositoryConnection;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.test.annotation.DirtiesContext;
Expand Down Expand Up @@ -516,4 +518,15 @@ void importImportsVocabularyLabelAndDescriptionInAllDeclaredLanguages() {
assertThat(result.get().getDescription().get(lang), not(emptyOrNullString()));
});
}

@ParameterizedTest
@CsvSource({Constants.MediaType.TURTLE, Constants.MediaType.RDF_XML, "application/n-triples"})
void supportsMediaTypeReturnsTrueForSupportedRDFBasedMediaTypes(String mediaType) {
assertTrue(SKOSImporter.supportsMediaType(mediaType));
}

@Test
void supportsMediaTypeReturnsFalseForUnsupportedMediaType() {
assertFalse(SKOSImporter.supportsMediaType(Constants.MediaType.EXCEL));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,19 +20,16 @@
import cz.cvut.kbss.termit.environment.Environment;
import cz.cvut.kbss.termit.environment.Generator;
import cz.cvut.kbss.termit.model.Vocabulary;
import cz.cvut.kbss.termit.persistence.dao.skos.SKOSImporter;
import cz.cvut.kbss.termit.service.importer.VocabularyImporter;
import cz.cvut.kbss.termit.service.importer.VocabularyImporters;
import cz.cvut.kbss.termit.service.repository.VocabularyRepositoryService;
import cz.cvut.kbss.termit.util.Configuration;
import cz.cvut.kbss.termit.util.Constants;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.context.ApplicationContext;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.web.multipart.MultipartFile;

Expand All @@ -48,22 +45,11 @@
class VocabularyRepositoryServiceImportTest {

@Mock
private SKOSImporter importer;

@Mock
private ApplicationContext context;

@Mock
private Configuration configuration;
private VocabularyImporters importer;

@InjectMocks
private VocabularyRepositoryService sut;

@BeforeEach
void setUp() {
when(context.getBean(SKOSImporter.class)).thenReturn(importer);
}

@Test
void passesInputStreamFromProvidedInputFileToImporter() throws IOException {
final MultipartFile input = new MockMultipartFile("vocabulary.ttl", "vocabulary.ttl",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package cz.cvut.kbss.termit.service.importer;

import cz.cvut.kbss.termit.util.Constants;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;

import static org.junit.jupiter.api.Assertions.*;

class ExcelImporterTest {

@ParameterizedTest
@CsvSource({Constants.MediaType.EXCEL, "application/vnd.ms-excel"})
void supportsMediaTypeReturnsTrueForSupportedExcelMediaType(String mediaType) {
assertTrue(ExcelImporter.supportsMediaType(mediaType));
}

@Test
void supportsMediaTypeReturnsFalseForUnsupportedMediaType() {
assertFalse(ExcelImporter.supportsMediaType("application/json"));
}
}
Loading

0 comments on commit bf234d7

Please sign in to comment.