/** * 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.sequencefile.driver; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import org.apache.hadoop.io.NullWritable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.asakusafw.dmdl.directio.sequencefile.driver.SequenceFileFormatTrait.Configuration; import com.asakusafw.dmdl.directio.util.DirectFileInputDescriptionGenerator; import com.asakusafw.dmdl.directio.util.DirectFileOutputDescriptionGenerator; import com.asakusafw.dmdl.java.emitter.EmitContext; import com.asakusafw.dmdl.java.spi.JavaDataModelDriver; import com.asakusafw.dmdl.semantics.ModelDeclaration; import com.asakusafw.runtime.directio.hadoop.HadoopFileFormat; import com.asakusafw.runtime.directio.hadoop.SequenceFileFormat; import com.asakusafw.utils.java.model.syntax.ClassDeclaration; import com.asakusafw.utils.java.model.syntax.FormalParameterDeclaration; import com.asakusafw.utils.java.model.syntax.MethodDeclaration; 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.syntax.TypeBodyDeclaration; import com.asakusafw.utils.java.model.util.AttributeBuilder; import com.asakusafw.utils.java.model.util.ExpressionBuilder; import com.asakusafw.utils.java.model.util.JavadocBuilder; import com.asakusafw.utils.java.model.util.TypeBuilder; /** * Emits {@link HadoopFileFormat} implementations. * @since 0.4.0 */ public class SequenceFileFormatEmitter extends JavaDataModelDriver { static final Logger LOG = LoggerFactory.getLogger(SequenceFileFormatEmitter.class); /** * Category name for this format. */ public static final String CATEGORY_STREAM = "sequencefile"; //$NON-NLS-1$ @Override public void generateResources(EmitContext context, ModelDeclaration model) throws IOException { if (isTarget(model) == false) { return; } Name supportName = generateFormat(context, model); generateInputDescription(context, supportName, model); generateOutputDescription(context, supportName, model); } private Name generateFormat(EmitContext context, ModelDeclaration model) throws IOException { assert context != null; assert model != null; EmitContext next = new EmitContext( context.getSemantics(), context.getConfiguration(), model, CATEGORY_STREAM, "{0}SequenceFileFormat"); //$NON-NLS-1$ LOG.debug("Generating SequenceFile format for {}", //$NON-NLS-1$ context.getQualifiedTypeName().toNameString()); FormatGenerator.emit(next, model, model.getTrait(SequenceFileFormatTrait.class).getConfiguration()); LOG.debug("Generated SequenceFile format for {}: {}", //$NON-NLS-1$ context.getQualifiedTypeName().toNameString(), next.getQualifiedTypeName().toNameString()); return next.getQualifiedTypeName(); } private void generateInputDescription( EmitContext context, Name formatClassName, ModelDeclaration model) throws IOException { EmitContext next = new EmitContext( context.getSemantics(), context.getConfiguration(), model, CATEGORY_STREAM, "Abstract{0}SequenceFileInputDescription"); //$NON-NLS-1$ DirectFileInputDescriptionGenerator.Description desc = new DirectFileInputDescriptionGenerator.Description( "SequenceFile input", context.getQualifiedTypeName()); //$NON-NLS-1$ desc.setFormatClassName(formatClassName); DirectFileInputDescriptionGenerator.generate(next, desc); } private void generateOutputDescription( EmitContext context, Name formatClassName, ModelDeclaration model) throws IOException { EmitContext next = new EmitContext( context.getSemantics(), context.getConfiguration(), model, CATEGORY_STREAM, "Abstract{0}SequenceFileOutputDescription"); //$NON-NLS-1$ DirectFileOutputDescriptionGenerator.Description desc = new DirectFileOutputDescriptionGenerator.Description( "SequenceFile output", context.getQualifiedTypeName()); //$NON-NLS-1$ desc.setFormatClassName(formatClassName); DirectFileOutputDescriptionGenerator.generate(next, desc); } private boolean isTarget(ModelDeclaration model) { assert model != null; SequenceFileFormatTrait trait = model.getTrait(SequenceFileFormatTrait.class); return trait != null; } private static final class FormatGenerator { private final EmitContext context; private final ModelDeclaration model; private final ModelFactory f; private FormatGenerator(EmitContext context, ModelDeclaration model, Configuration configuration) { assert context != null; assert model != null; assert configuration != null; this.context = context; this.model = model; this.f = context.getModelFactory(); } static void emit(EmitContext context, ModelDeclaration model, Configuration conf) throws IOException { assert context != null; assert model != null; assert conf != null; FormatGenerator emitter = new FormatGenerator(context, model, conf); emitter.emit(); } private void emit() throws IOException { ClassDeclaration decl = f.newClassDeclaration( new JavadocBuilder(f) .inline("SequenceFile format for {0}.", d -> d.linkType(context.resolve(model.getSymbol()))) .toJavadoc(), new AttributeBuilder(f) .Public() .toAttributes(), context.getTypeName(), f.newParameterizedType( context.resolve(SequenceFileFormat.class), context.resolve(NullWritable.class), context.resolve(model.getSymbol()), context.resolve(model.getSymbol())), Collections.emptyList(), createMembers()); context.emit(decl); } private List<TypeBodyDeclaration> createMembers() { List<TypeBodyDeclaration> results = new ArrayList<>(); results.add(createGetSupportedType()); results.add(createCreateKeyObject()); results.add(createCreateValueObject()); results.add(createCopyToModel()); results.add(createCopyFromModel()); return results; } private MethodDeclaration createGetSupportedType() { MethodDeclaration decl = f.newMethodDeclaration( null, new AttributeBuilder(f) .annotation(context.resolve(Override.class)) .Public() .toAttributes(), f.newParameterizedType( context.resolve(Class.class), context.resolve(model.getSymbol())), f.newSimpleName("getSupportedType"), //$NON-NLS-1$ Collections.emptyList(), Arrays.asList(new Statement[] { new TypeBuilder(f, context.resolve(model.getSymbol())) .dotClass() .toReturnStatement() })); return decl; } private MethodDeclaration createCreateKeyObject() { return f.newMethodDeclaration( null, new AttributeBuilder(f) .annotation(context.resolve(Override.class)) .Public() .toAttributes(), context.resolve(NullWritable.class), f.newSimpleName("createKeyObject"), //$NON-NLS-1$ Collections.emptyList(), Arrays.asList(new TypeBuilder(f, context.resolve(NullWritable.class)) .method("get") //$NON-NLS-1$ .toReturnStatement())); } private MethodDeclaration createCreateValueObject() { return f.newMethodDeclaration( null, new AttributeBuilder(f) .annotation(context.resolve(Override.class)) .Public() .toAttributes(), context.resolve(model.getSymbol()), f.newSimpleName("createValueObject"), //$NON-NLS-1$ Collections.emptyList(), Arrays.asList(new TypeBuilder(f, context.resolve(model.getSymbol())) .newObject() .toReturnStatement())); } private MethodDeclaration createCopyToModel() { SimpleName key = f.newSimpleName("key"); //$NON-NLS-1$ SimpleName value = f.newSimpleName("value"); //$NON-NLS-1$ SimpleName internal = f.newSimpleName("model"); //$NON-NLS-1$ return f.newMethodDeclaration( null, new AttributeBuilder(f) .annotation(context.resolve(Override.class)) .Public() .toAttributes(), context.resolve(void.class), f.newSimpleName("copyToModel"), //$NON-NLS-1$ Arrays.asList(new FormalParameterDeclaration[] { f.newFormalParameterDeclaration(context.resolve(NullWritable.class), key), f.newFormalParameterDeclaration(context.resolve(model.getSymbol()), value), f.newFormalParameterDeclaration(context.resolve(model.getSymbol()), internal), }), Arrays.asList(new ExpressionBuilder(f, internal) .method("copyFrom", value) //$NON-NLS-1$ .toStatement())); } private MethodDeclaration createCopyFromModel() { SimpleName key = f.newSimpleName("key"); //$NON-NLS-1$ SimpleName value = f.newSimpleName("value"); //$NON-NLS-1$ SimpleName internal = f.newSimpleName("model"); //$NON-NLS-1$ return f.newMethodDeclaration( null, new AttributeBuilder(f) .annotation(context.resolve(Override.class)) .Public() .toAttributes(), context.resolve(void.class), f.newSimpleName("copyFromModel"), //$NON-NLS-1$ Arrays.asList(new FormalParameterDeclaration[] { f.newFormalParameterDeclaration(context.resolve(model.getSymbol()), internal), f.newFormalParameterDeclaration(context.resolve(NullWritable.class), key), f.newFormalParameterDeclaration(context.resolve(model.getSymbol()), value), }), Arrays.asList(new ExpressionBuilder(f, value) .method("copyFrom", internal) //$NON-NLS-1$ .toStatement())); } } }