/** * Copyright 2011-2017 Asakusa Framework Team. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.asakusafw.dmdl.directio.text.tabular; import static com.asakusafw.dmdl.directio.text.TextFormatConstants.*; import java.io.IOException; import java.util.ArrayList; import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.asakusafw.dmdl.directio.text.AbstractTextStreamFormatGenerator; import com.asakusafw.dmdl.directio.text.EscapeSettings; import com.asakusafw.dmdl.directio.text.TextFormatSettings; import com.asakusafw.dmdl.directio.util.DirectFileInputDescriptionGenerator; import com.asakusafw.dmdl.directio.util.DirectFileOutputDescriptionGenerator; import com.asakusafw.dmdl.directio.util.MapValue; import com.asakusafw.dmdl.java.emitter.EmitContext; import com.asakusafw.dmdl.java.spi.JavaDataModelDriver; import com.asakusafw.dmdl.semantics.ModelDeclaration; import com.asakusafw.runtime.io.text.tabular.EscapeSequence; import com.asakusafw.runtime.io.text.tabular.TabularTextFormat; import com.asakusafw.utils.java.model.syntax.ModelFactory; import com.asakusafw.utils.java.model.syntax.Name; import com.asakusafw.utils.java.model.syntax.SimpleName; import com.asakusafw.utils.java.model.syntax.Statement; import com.asakusafw.utils.java.model.util.ExpressionBuilder; import com.asakusafw.utils.java.model.util.TypeBuilder; /** * Emits Direct I/O data format classes about tabular text. * @since 0.9.1 */ public class TabularTextEmitter extends JavaDataModelDriver { static final Logger LOG = LoggerFactory.getLogger(TabularTextEmitter.class); @Override public void generateResources(EmitContext context, ModelDeclaration model) throws IOException { if (TabularTextTrait.find(model).isPresent() == false) { return; } Name supportName = generateFormat(context, model); generateInputDescription(context, supportName, model); generateOutputDescription(context, supportName, model); } private static Name generateFormat(EmitContext context, ModelDeclaration model) throws IOException { assert context != null; assert model != null; TabularTextTrait trait = TabularTextTrait.get(model); EmitContext next = new EmitContext( context.getSemantics(), context.getConfiguration(), model, PACKAGE_SEGMENT, "{0}TabularTextFormat"); //$NON-NLS-1$ LOG.debug("Generating tabular text format for {}", //$NON-NLS-1$ context.getQualifiedTypeName().toNameString()); FormatGenerator.emit(next, model, trait); LOG.debug("Generated tabular text format for {}: {}", //$NON-NLS-1$ context.getQualifiedTypeName().toNameString(), next.getQualifiedTypeName().toNameString()); return next.getQualifiedTypeName(); } private static void generateInputDescription( EmitContext context, Name formatClassName, ModelDeclaration model) throws IOException { EmitContext next = new EmitContext( context.getSemantics(), context.getConfiguration(), model, PACKAGE_SEGMENT, "Abstract{0}TabularTextInputDescription"); //$NON-NLS-1$ DirectFileInputDescriptionGenerator.Description desc = new DirectFileInputDescriptionGenerator.Description( "Tabular text file input", context.getQualifiedTypeName()); //$NON-NLS-1$ desc.setFormatClassName(formatClassName); DirectFileInputDescriptionGenerator.generate(next, desc); } private static void generateOutputDescription( EmitContext context, Name formatClassName, ModelDeclaration model) throws IOException { EmitContext next = new EmitContext( context.getSemantics(), context.getConfiguration(), model, PACKAGE_SEGMENT, "Abstract{0}TabularTextOutputDescription"); //$NON-NLS-1$ DirectFileOutputDescriptionGenerator.Description desc = new DirectFileOutputDescriptionGenerator.Description( "Tabular text file output", context.getQualifiedTypeName()); //$NON-NLS-1$ desc.setFormatClassName(formatClassName); DirectFileOutputDescriptionGenerator.generate(next, desc); } private static final class FormatGenerator extends AbstractTextStreamFormatGenerator { private final TabularTextTrait root; private final ModelFactory f; private FormatGenerator(EmitContext context, ModelDeclaration model, TabularTextTrait root) { super(context, model, root.getFormatSettings(), root.getFieldSettings()); this.root = root; this.f = context.getModelFactory(); } static void emit(EmitContext context, ModelDeclaration model, TabularTextTrait trait) throws IOException { new FormatGenerator(context, model, trait).emit(Messages.getString("TabularTextEmitter.javadocTitle")); //$NON-NLS-1$ } @Override protected List<Statement> createGetTextFormatInternal() { SimpleName builder = f.newSimpleName("builder"); //$NON-NLS-1$ List<Statement> statements = new ArrayList<>(); statements.add(new TypeBuilder(f, context.resolve(TabularTextFormat.class)) .method("builder") //$NON-NLS-1$ .toLocalVariableDeclaration(context.resolve(TabularTextFormat.Builder.class), builder)); buildTextFormat(statements, builder); statements.add(new ExpressionBuilder(f, builder) .method("build") //$NON-NLS-1$ .toReturnStatement()); return statements; } private void buildTextFormat(List<Statement> statements, SimpleName builder) { TextFormatSettings formats = root.getFormatSettings(); EscapeSettings escapes = root.getEscapeSettings(); formats.getCharset().ifPresent(v -> statements.add(new ExpressionBuilder(f, builder) .method("withCharset", resolve(v.name())) //$NON-NLS-1$ .toStatement())); formats.getLineSeparator().ifPresent(v -> statements.add(new ExpressionBuilder(f, builder) .method("withLineSeparator", resolve(v)) //$NON-NLS-1$ .toStatement())); formats.getFieldSeparator().ifPresent(v -> statements.add(new ExpressionBuilder(f, builder) .method("withFieldSeparator", resolve(v)) //$NON-NLS-1$ .toStatement())); escapes.getCharacter().ifPresent(c -> { ExpressionBuilder escapeBuilder = new TypeBuilder(f, context.resolve(EscapeSequence.class)) .method("builder", resolve(c)); //$NON-NLS-1$ escapes.getEscapeLineSeparator().ifPresent(v -> { if (v) { escapeBuilder.method("addLineSeparator"); //$NON-NLS-1$ } }); for (MapValue.Entry<Character, Character> entry : escapes.getSequences()) { Character key = entry.getKey(); Character value = entry.getValue(); if (value == null) { escapeBuilder.method("addNullMapping", resolve(key)); //$NON-NLS-1$ } else { escapeBuilder.method("addMapping", resolve(key), resolve(value)); //$NON-NLS-1$ } } statements.add(new ExpressionBuilder(f, builder) .method("withEscapeSequence", escapeBuilder //$NON-NLS-1$ .method("build") //$NON-NLS-1$ .toExpression()) .toStatement()); }); formats.getInputTransformerClass().ifPresent(v -> statements.add(new ExpressionBuilder(f, builder) .method("withInputTransformer", new TypeBuilder(f, resolve(v)) //$NON-NLS-1$ .constructorReference() .toExpression()) .toStatement())); formats.getOutputTransformerClass().ifPresent(v -> statements.add(new ExpressionBuilder(f, builder) .method("withOutputTransformer", new TypeBuilder(f, resolve(v)) //$NON-NLS-1$ .constructorReference() .toExpression()) .toStatement())); } @Override protected boolean isSplittableInternal() { return root.getEscapeSettings().getEscapeLineSeparator().orElse(false) == false; } } }