Skip to content

Commit

Permalink
refactor: split resource map from resource factory
Browse files Browse the repository at this point in the history
  • Loading branch information
jruaux committed Nov 26, 2024
1 parent 26f264f commit f3bb4fe
Show file tree
Hide file tree
Showing 9 changed files with 85 additions and 87 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,13 @@ public ReaderFactory getReaderFactory(MimeType type) {

public static FileReaderRegistry defaultReaderRegistry() {
FileReaderRegistry registry = new FileReaderRegistry();
registry.register(ResourceFactory.JSON, new JsonReaderFactory());
registry.register(ResourceFactory.JSON_LINES, new JsonLinesReaderFactory());
registry.register(ResourceFactory.XML, new XmlReaderFactory());
registry.register(ResourceFactory.CSV, new DelimitedReaderFactory(FileOptions.DELIMITER_COMMA));
registry.register(ResourceFactory.PSV, new DelimitedReaderFactory(FileOptions.DELIMITER_PIPE));
registry.register(ResourceFactory.TSV, new DelimitedReaderFactory(FileOptions.DELIMITER_TAB));
registry.register(ResourceFactory.TEXT, new FixedWidthReaderFactory());
registry.register(RiotResourceMap.JSON, new JsonReaderFactory());
registry.register(RiotResourceMap.JSON_LINES, new JsonLinesReaderFactory());
registry.register(RiotResourceMap.XML, new XmlReaderFactory());
registry.register(RiotResourceMap.CSV, new DelimitedReaderFactory(FileOptions.DELIMITER_COMMA));
registry.register(RiotResourceMap.PSV, new DelimitedReaderFactory(FileOptions.DELIMITER_PIPE));
registry.register(RiotResourceMap.TSV, new DelimitedReaderFactory(FileOptions.DELIMITER_TAB));
registry.register(RiotResourceMap.TEXT, new FixedWidthReaderFactory());
return registry;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,13 @@ public WriterFactory getWriterFactory(MimeType type) {

public static FileWriterRegistry defaultWriterRegistry() {
FileWriterRegistry registry = new FileWriterRegistry();
registry.register(ResourceFactory.JSON, new JsonWriterFactory());
registry.register(ResourceFactory.JSON_LINES, new JsonLinesWriterFactory());
registry.register(ResourceFactory.XML, new XmlWriterFactory());
registry.register(ResourceFactory.CSV, new DelimitedWriterFactory(FileOptions.DELIMITER_COMMA));
registry.register(ResourceFactory.PSV, new DelimitedWriterFactory(FileOptions.DELIMITER_PIPE));
registry.register(ResourceFactory.TSV, new DelimitedWriterFactory(FileOptions.DELIMITER_TAB));
registry.register(ResourceFactory.TEXT, new FormattedWriterFactory());
registry.register(RiotResourceMap.JSON, new JsonWriterFactory());
registry.register(RiotResourceMap.JSON_LINES, new JsonLinesWriterFactory());
registry.register(RiotResourceMap.XML, new XmlWriterFactory());
registry.register(RiotResourceMap.CSV, new DelimitedWriterFactory(FileOptions.DELIMITER_COMMA));
registry.register(RiotResourceMap.PSV, new DelimitedWriterFactory(FileOptions.DELIMITER_PIPE));
registry.register(RiotResourceMap.TSV, new DelimitedWriterFactory(FileOptions.DELIMITER_TAB));
registry.register(RiotResourceMap.TEXT, new FormattedWriterFactory());
return registry;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package com.redis.riot.file;

import java.io.IOException;
import java.net.FileNameMap;
import java.util.HashSet;
import java.util.Set;
import java.util.zip.GZIPInputStream;
Expand All @@ -11,58 +10,13 @@
import org.springframework.core.io.Resource;
import org.springframework.core.io.WritableResource;
import org.springframework.util.Assert;
import org.springframework.util.MimeType;
import org.springframework.util.MimeTypeUtils;

public class ResourceFactory {

public static final String GZ_SUFFIX = ".gz";

public static final MimeType CSV = new MimeType("text", "csv");
public static final MimeType PSV = new MimeType("text", "psv");
public static final MimeType TSV = new MimeType("text", "tsv");
public static final MimeType TEXT = new MimeType("text", "plain");
public static final MimeType JSON = MimeTypeUtils.APPLICATION_JSON;
public static final MimeType JSON_LINES = new MimeType("application", "jsonlines");
public static final MimeType XML = MimeTypeUtils.APPLICATION_XML;

private ResourceMap resourceMap = defaultResourceMap();
private Set<ProtocolResolver> protocolResolvers = new HashSet<>();

public MimeType type(Resource resource) {
return MimeType.valueOf(resourceMap.getContentTypeFor(resource));
}

public MimeType type(Resource resource, FileOptions options) {
if (options.getContentType() == null) {
return MimeType.valueOf(resourceMap.getContentTypeFor(resource));
}
return options.getContentType();
}

private static class JsonLinesFileNameMap implements FileNameMap {

public static final String JSONL_SUFFIX = ".jsonl";

@Override
public String getContentTypeFor(String fileName) {
if (fileName == null) {
return null;
}
if (fileName.endsWith(JSONL_SUFFIX)) {
return JSON_LINES.toString();
}
return null;
}

}

public static ResourceMap defaultResourceMap() {
RiotResourceMap resourceMap = new RiotResourceMap();
resourceMap.addFileNameMap(new JsonLinesFileNameMap());
return resourceMap;
}

public void addProtocolResolver(ProtocolResolver protocolResolver) {
protocolResolvers.add(protocolResolver);
}
Expand Down Expand Up @@ -110,12 +64,4 @@ public static String stripGzipSuffix(String filename) {
return filename;
}

public ResourceMap getResourceMap() {
return resourceMap;
}

public void setResourceMap(ResourceMap resourceMap) {
this.resourceMap = resourceMap;
}

}
Original file line number Diff line number Diff line change
@@ -1,9 +1,19 @@
package com.redis.riot.file;

import org.springframework.core.io.Resource;
import org.springframework.util.MimeType;
import org.springframework.util.MimeTypeUtils;

public interface ResourceMap {

String getContentTypeFor(Resource resource);
MimeType CSV = new MimeType("text", "csv");
MimeType PSV = new MimeType("text", "psv");
MimeType TSV = new MimeType("text", "tsv");
MimeType TEXT = new MimeType("text", "plain");
MimeType JSON = MimeTypeUtils.APPLICATION_JSON;
MimeType JSON_LINES = new MimeType("application", "jsonlines");
MimeType XML = MimeTypeUtils.APPLICATION_XML;

MimeType getContentTypeFor(Resource resource);

}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import java.util.Set;

import org.springframework.core.io.Resource;
import org.springframework.util.MimeType;

public class RiotResourceMap implements ResourceMap {

Expand All @@ -18,7 +19,7 @@ public void addFileNameMap(FileNameMap map) {
}

@Override
public String getContentTypeFor(Resource resource) {
public MimeType getContentTypeFor(Resource resource) {
String type = null;
if (resource.isFile()) {
try {
Expand All @@ -30,22 +31,44 @@ public String getContentTypeFor(Resource resource) {
if (type == null) {
return getContentTypeFor(resource.getFilename());
}
return type;
return MimeType.valueOf(type);
}

public String getContentTypeFor(String filename) {
public MimeType getContentTypeFor(String filename) {
String normalizedFilename = ResourceFactory.stripGzipSuffix(filename);
String type = URLConnection.guessContentTypeFromName(normalizedFilename);
if (type != null) {
return type;
return MimeType.valueOf(type);
}
for (FileNameMap nameMap : fileNameMaps) {
String mapType = nameMap.getContentTypeFor(normalizedFilename);
if (mapType != null) {
return mapType;
return MimeType.valueOf(mapType);
}
}
throw new IllegalArgumentException("Could not determine type of " + filename);
}

public static RiotResourceMap defaultResourceMap() {
RiotResourceMap resourceMap = new RiotResourceMap();
resourceMap.addFileNameMap(new JsonLinesFileNameMap());
return resourceMap;
}

private static class JsonLinesFileNameMap implements FileNameMap {

public static final String JSONL_SUFFIX = ".jsonl";

@Override
public String getContentTypeFor(String fileName) {
if (fileName == null) {
return null;
}
if (fileName.endsWith(JSONL_SUFFIX)) {
return JSON_LINES.toString();
}
return null;
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ public class ReaderTests {
public static final String JSON_GZ_URL = "http://storage.googleapis.com/jrx/beers.json.gz";

private final ResourceFactory resourceFactory = new ResourceFactory();
private final ResourceMap resourceMap = RiotResourceMap.defaultResourceMap();
private final FileReaderRegistry registry = FileReaderRegistry.defaultReaderRegistry();

@Test
Expand Down Expand Up @@ -103,7 +104,7 @@ private void assertRead(String location, Class<?> expectedType, int expectedCoun
private void assertRead(String location, ReadOptions options, Class<?> expectedType, int expectedCount)
throws Exception {
Resource resource = resourceFactory.resource(location, options);
MimeType type = resourceFactory.type(resource);
MimeType type = resourceMap.getContentTypeFor(resource);
ItemReader<?> reader = registry.getReaderFactory(type).create(resource, options);
Assertions.assertNotNull(reader);
List<?> items = readAll(reader);
Expand Down
13 changes: 11 additions & 2 deletions plugins/riot/src/main/java/com/redis/riot/AbstractFileExport.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
import com.redis.riot.core.Step;
import com.redis.riot.file.FileWriterRegistry;
import com.redis.riot.file.ResourceFactory;
import com.redis.riot.file.ResourceMap;
import com.redis.riot.file.RiotResourceMap;
import com.redis.riot.file.RuntimeIOException;
import com.redis.riot.file.StdOutProtocolResolver;
import com.redis.riot.file.WriteOptions;
Expand All @@ -36,7 +38,7 @@
public abstract class AbstractFileExport extends AbstractRedisExportCommand {

private Set<MimeType> flatFileTypes = new HashSet<>(
Arrays.asList(ResourceFactory.CSV, ResourceFactory.PSV, ResourceFactory.TSV, ResourceFactory.TEXT));
Arrays.asList(ResourceMap.CSV, ResourceMap.PSV, ResourceMap.TSV, ResourceMap.TEXT));

@Parameters(arity = "0..1", description = "File path or URL. If omitted, export is written to stdout.", paramLabel = "FILE")
private String file = StdOutProtocolResolver.DEFAULT_FILENAME;
Expand All @@ -49,16 +51,22 @@ public abstract class AbstractFileExport extends AbstractRedisExportCommand {

private FileWriterRegistry writerRegistry;
private ResourceFactory resourceFactory;
private ResourceMap resourceMap;
private WriteOptions writeOptions;

@Override
protected void initialize() throws RiotInitializationException {
super.initialize();
writerRegistry = writerRegistry();
resourceFactory = resourceFactory();
resourceMap = resourceMap();
writeOptions = writeOptions();
}

protected RiotResourceMap resourceMap() {
return RiotResourceMap.defaultResourceMap();
}

protected FileWriterRegistry writerRegistry() {
return FileWriterRegistry.defaultWriterRegistry();
}
Expand Down Expand Up @@ -95,7 +103,8 @@ public void setFlatFileTypes(MimeType... types) {
} catch (IOException e) {
throw new RuntimeIOException(String.format("Could not create resource from file %s", file), e);
}
MimeType type = resourceFactory.type(resource, writeOptions);
MimeType type = writeOptions.getContentType() == null ? resourceMap.getContentTypeFor(resource)
: writeOptions.getContentType();
WriterFactory writerFactory = writerRegistry.getWriterFactory(type);
Assert.notNull(writerFactory, String.format("No writer found for file %s", file));
ItemWriter<?> writer = writerFactory.create(resource, writeOptions);
Expand Down
13 changes: 11 additions & 2 deletions plugins/riot/src/main/java/com/redis/riot/AbstractFileImport.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@
import com.redis.riot.file.ReadOptions;
import com.redis.riot.file.ReaderFactory;
import com.redis.riot.file.ResourceFactory;
import com.redis.riot.file.ResourceMap;
import com.redis.riot.file.RiotResourceMap;
import com.redis.riot.file.RuntimeIOException;
import com.redis.riot.file.StdInProtocolResolver;
import com.redis.riot.function.MapToFieldFunction;
Expand All @@ -46,7 +48,7 @@ public abstract class AbstractFileImport extends AbstractRedisImportCommand {

public static final String STDIN_FILENAME = "-";
private static final Set<MimeType> keyValueTypes = new HashSet<>(
Arrays.asList(ResourceFactory.JSON, ResourceFactory.JSON_LINES, ResourceFactory.XML));
Arrays.asList(ResourceMap.JSON, ResourceMap.JSON_LINES, ResourceMap.XML));

@Parameters(arity = "1..*", description = "Files or URLs to import. Use '-' to read from stdin.", paramLabel = "FILE")
private List<String> files;
Expand All @@ -58,6 +60,7 @@ public abstract class AbstractFileImport extends AbstractRedisImportCommand {
private Map<String, Pattern> regexes = new LinkedHashMap<>();

private FileReaderRegistry readerRegistry;
private RiotResourceMap resourceMap;
private ResourceFactory resourceFactory;
private ReadOptions readOptions;

Expand All @@ -67,9 +70,14 @@ protected void initialize() throws RiotInitializationException {
Assert.notEmpty(files, "No file specified");
readerRegistry = readerRegistry();
resourceFactory = resourceFactory();
resourceMap = resourceMap();
readOptions = readOptions();
}

protected RiotResourceMap resourceMap() {
return RiotResourceMap.defaultResourceMap();
}

protected FileReaderRegistry readerRegistry() {
return FileReaderRegistry.defaultReaderRegistry();
}
Expand All @@ -94,7 +102,8 @@ protected Job job() {
} catch (IOException e) {
throw new RuntimeIOException(String.format("Could not create resource from %s", location), e);
}
MimeType type = resourceFactory.type(resource, readOptions);
MimeType type = readOptions.getContentType() == null ? resourceMap.getContentTypeFor(resource)
: readOptions.getContentType();
ReaderFactory readerFactory = readerRegistry.getReaderFactory(type);
Assert.notNull(readerFactory, () -> String.format("No reader found for file %s", location));
ItemReader<?> reader = readerFactory.create(resource, readOptions);
Expand Down
16 changes: 8 additions & 8 deletions plugins/riot/src/main/java/com/redis/riot/FileTypeArgs.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

import org.springframework.util.MimeType;

import com.redis.riot.file.ResourceFactory;
import com.redis.riot.file.ResourceMap;

import picocli.CommandLine.ITypeConverter;
import picocli.CommandLine.Option;
Expand All @@ -29,13 +29,13 @@ public void setType(MimeType type) {

public static Map<String, MimeType> typeMap() {
Map<String, MimeType> map = new HashMap<>();
map.put("csv", ResourceFactory.CSV);
map.put("psv", ResourceFactory.PSV);
map.put("tsv", ResourceFactory.TSV);
map.put("fw", ResourceFactory.TEXT);
map.put("json", ResourceFactory.JSON);
map.put("jsonl", ResourceFactory.JSON_LINES);
map.put("xml", ResourceFactory.XML);
map.put("csv", ResourceMap.CSV);
map.put("psv", ResourceMap.PSV);
map.put("tsv", ResourceMap.TSV);
map.put("fw", ResourceMap.TEXT);
map.put("json", ResourceMap.JSON);
map.put("jsonl", ResourceMap.JSON_LINES);
map.put("xml", ResourceMap.XML);
return map;
}

Expand Down

0 comments on commit f3bb4fe

Please sign in to comment.