package org.embulk.spi.util; import java.util.List; import java.util.Map; import com.google.common.base.Optional; import org.joda.time.DateTimeZone; import org.jruby.embed.ScriptingContainer; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import org.embulk.config.Config; import org.embulk.config.ConfigDefault; import org.embulk.config.ConfigInject; import org.embulk.config.ConfigSource; import org.embulk.config.Task; import org.embulk.spi.Schema; import org.embulk.spi.Column; import org.embulk.spi.BufferAllocator; import org.embulk.spi.PageBuilder; import org.embulk.spi.PageOutput; import org.embulk.spi.time.TimestampFormatter; import org.embulk.spi.time.TimestampParser; import org.embulk.spi.time.TimestampFormat; import org.embulk.spi.util.dynamic.SkipColumnSetter; public class DynamicPageBuilder implements AutoCloseable { private final PageBuilder pageBuilder; private final Schema schema; private final DynamicColumnSetter[] setters; private final Map<String, DynamicColumnSetter> columnLookup; public static interface BuilderTask extends Task { @Config("default_timezone") @ConfigDefault("\"UTC\"") public DateTimeZone getDefaultTimeZone(); @Config("column_options") @ConfigDefault("{}") public Map<String, ConfigSource> getColumnOptions(); // required by TimestampFormatter @ConfigInject public ScriptingContainer getJRuby(); } public static interface ColumnOption extends Task { @Config("timestamp_format") @ConfigDefault("\"%Y-%m-%d %H:%M:%S.%6N\"") public TimestampFormat getTimestampFormat(); @Config("timezone") @ConfigDefault("null") public Optional<DateTimeZone> getTimeZone(); } public DynamicPageBuilder(BuilderTask task, BufferAllocator allocator, Schema schema, PageOutput output) { this.pageBuilder = new PageBuilder(allocator, schema, output); this.schema = schema; // TODO configurable default value DynamicColumnSetterFactory factory = new DynamicColumnSetterFactory(task, DynamicColumnSetterFactory.nullDefaultValue()); ImmutableList.Builder<DynamicColumnSetter> setters = ImmutableList.builder(); ImmutableMap.Builder<String, DynamicColumnSetter> lookup = ImmutableMap.builder(); for (Column c : schema.getColumns()) { DynamicColumnSetter setter = factory.newColumnSetter(pageBuilder, c); setters.add(setter); lookup.put(c.getName(), setter); } this.setters = setters.build().toArray(new DynamicColumnSetter[0]); this.columnLookup = lookup.build(); } public List<Column> getColumns() { return schema.getColumns(); } public DynamicColumnSetter column(Column c) { return setters[c.getIndex()]; } public DynamicColumnSetter column(int index) { if (index < 0 || setters.length <= index) { throw new DynamicColumnNotFoundException("Column index '"+index+"' is not exist"); } return setters[index]; } public DynamicColumnSetter lookupColumn(String columnName) { DynamicColumnSetter setter = columnLookup.get(columnName); if (setter == null) { throw new DynamicColumnNotFoundException("Column '"+columnName+"' is not exist"); } return setter; } public DynamicColumnSetter columnOrSkip(int index) { if (index < 0 || setters.length <= index) { return SkipColumnSetter.get(); } return setters[index]; } public DynamicColumnSetter columnOrSkip(String columnName) { DynamicColumnSetter setter = columnLookup.get(columnName); if (setter == null) { return SkipColumnSetter.get(); } return setter; } // for jruby protected DynamicColumnSetter columnOrNull(int index) { if (index < 0 || setters.length <= index) { return null; } return setters[index]; } // for jruby protected DynamicColumnSetter columnOrNull(String columnName) { return columnLookup.get(columnName); } public void addRecord() { pageBuilder.addRecord(); } public void flush() { pageBuilder.flush(); } public void finish() { pageBuilder.finish(); } @Override public void close() { pageBuilder.close(); } }