Package com.asakusafw.dmdl.thundergate.emitter

Source Code of com.asakusafw.dmdl.thundergate.emitter.ThunderGateModelEmitter

/**
* Copyright 2011-2014 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.thundergate.emitter;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.MessageFormat;
import java.util.Collections;
import java.util.Map;
import java.util.TreeMap;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.asakusafw.dmdl.model.AstAttribute;
import com.asakusafw.dmdl.model.AstLiteral;
import com.asakusafw.dmdl.model.AstModelDefinition;
import com.asakusafw.dmdl.model.AstScript;
import com.asakusafw.dmdl.model.LiteralKind;
import com.asakusafw.dmdl.parser.DmdlEmitter;
import com.asakusafw.dmdl.thundergate.Configuration;
import com.asakusafw.dmdl.thundergate.Constants;
import com.asakusafw.dmdl.thundergate.model.JoinedModelDescription;
import com.asakusafw.dmdl.thundergate.model.ModelDescription;
import com.asakusafw.dmdl.thundergate.model.ModelProperty;
import com.asakusafw.dmdl.thundergate.model.PropertyType;
import com.asakusafw.dmdl.thundergate.model.PropertyTypeKind;
import com.asakusafw.dmdl.thundergate.model.SummarizedModelDescription;
import com.asakusafw.dmdl.thundergate.model.TableModelDescription;

/**
* Emits ThunderGate data models as DMDL.
* @since 0.2.0
* @version 0.2.3
*/
public class ThunderGateModelEmitter {

    static final Logger LOG = LoggerFactory.getLogger(ThunderGateModelEmitter.class);

    private final Configuration config;

    /**
     * Creates and returns a new instance.
     * @param config the configuration
     * @throws IllegalArgumentException if some parameters were {@code null}
     */
    public ThunderGateModelEmitter(Configuration config) {
        if (config == null) {
            throw new IllegalArgumentException("config must not be null"); //$NON-NLS-1$
        }
        this.config = config;
    }

    /**
     * Convert the ThunderGete model description into DMDL model and emit DMDL script.
     * @param model target model
     * @throws IOException if failed to emit DMDL script
     * @throws IllegalArgumentException if some parameters were {@code null}
     */
    public void emit(ModelDescription model) throws IOException {
        if (model == null) {
            throw new IllegalArgumentException("model must not be null"); //$NON-NLS-1$
        }
        AstScript script = convert(model);
        String name = model.getReference().getSimpleName();
        emit(name, script);
    }

    private AstScript convert(ModelDescription model) {
        assert model != null;
        AstModelDefinition<?> def;
        if (model instanceof TableModelDescription) {
            TableModelDescription tableModel = (TableModelDescription) model;
            AstAttribute cacheSupport = generateCacheSupport(tableModel);
            if (cacheSupport == null) {
                def = RecordModelGenerator.generate(tableModel);
            } else {
                def = RecordModelGenerator.generate(tableModel, cacheSupport);
            }
        } else if (model instanceof JoinedModelDescription) {
            def = JoinedModelGenerator.generate((JoinedModelDescription) model);
        } else if (model instanceof SummarizedModelDescription) {
            def = SummarizedModelGenerator.generate((SummarizedModelDescription) model);
        } else {
            throw new AssertionError(model);
        }
        return new AstScript(null, Collections.singletonList(def));
    }

    private AstAttribute generateCacheSupport(TableModelDescription model) {
        assert model != null;
        if (config.getSidColumn() == null) {
            return null;
        }

        Map<String, ModelProperty> properties = new TreeMap<String, ModelProperty>(String.CASE_INSENSITIVE_ORDER);
        for (ModelProperty property : model.getProperties()) {
            properties.put(property.getSource().getName(), property);
        }

        ModelProperty sid = properties.get(config.getSidColumn());
        if (sid == null) {
            LOG.warn("テーブル{}にはカラム{}が定義されていないため、キャッシュはサポートされません",
                    model.getReference().getSimpleName(),
                    config.getSidColumn());
            return null;
        }
        if (sid.getType().getKind() != PropertyTypeKind.LONG) {
            LOG.warn("テーブル{}のカラム{}がBIGINTでないため、キャッシュはサポートされません",
                    model.getReference().getSimpleName(),
                    config.getSidColumn());
            return null;
        }

        ModelProperty timestamp = properties.get(config.getTimestampColumn());
        if (timestamp == null) {
            LOG.warn("テーブル{}にはカラム{}が定義されていないため、キャッシュはサポートされません",
                    model.getReference().getSimpleName(),
                    config.getTimestampColumn());
            return null;
        }
        if (timestamp.getType().getKind() != PropertyTypeKind.DATETIME) {
            LOG.warn("テーブル{}のカラム{}がDATETIMEでないため、キャッシュはサポートされません",
                    model.getReference().getSimpleName(),
                    config.getTimestampColumn());
            return null;
        }

        if (config.getDeleteFlagColumn() != null) {
            ModelProperty deleteFlag = properties.get(config.getDeleteFlagColumn());
            if (deleteFlag == null) {
                LOG.info("テーブル{}のカラム{}が定義されていないため、このテーブルに対する論理削除機能は無効化されます",
                        model.getReference().getSimpleName(),
                        config.getDeleteFlagColumn());
            } else if (acceptsLiteral(deleteFlag.getType(), config.getDeleteFlagValue()) == false) {
                LOG.warn("テーブル{}のカラム{}は指定した論理削除の値({})を利用できないため、キャッシュはサポートされません", new Object[] {
                        model.getReference().getSimpleName(),
                        config.getDeleteFlagColumn(),
                        config.getDeleteFlagValue(),
                });
                return null;
            } else {
                return AstBuilder.getCacheSupport(sid, timestamp, deleteFlag, config.getDeleteFlagValue());
            }
        }
        return AstBuilder.getCacheSupport(sid, timestamp);
    }

    private boolean acceptsLiteral(PropertyType type, AstLiteral value) {
        assert type != null;
        assert value != null;
        LiteralKind literalKind = value.getKind();
        switch (type.getKind()) {
        case BOOLEAN:
            return literalKind == LiteralKind.BOOLEAN;
        case BYTE:
        case SHORT:
        case INT:
        case LONG:
            return literalKind == LiteralKind.INTEGER;
        case STRING:
            return literalKind == LiteralKind.STRING;
        default:
            return false;
        }
    }

    private void emit(String name, AstScript script) throws IOException {
        assert name != null;
        assert script != null;
        PrintWriter output = open(name);
        try {
            DmdlEmitter.emit(script, output);
            if (output.checkError()) {
                throw new IOException(MessageFormat.format(
                        "Cannot output DMDL {0}",
                        name));
            }
        } finally {
            output.close();
        }
    }

    private PrintWriter open(String name) throws IOException {
        if (name == null) {
            throw new IllegalArgumentException("name must not be null"); //$NON-NLS-1$
        }
        File file = new File(config.getOutput(), name + Constants.DMDL_LIKE_EXTENSION);
        File directory = file.getParentFile();
        if (directory.exists() == false && directory.mkdirs() == false) {
            throw new IOException(MessageFormat.format(
                    "Failed to create output directory: {0}",
                    directory));
        }
        PrintWriter writer = new PrintWriter(file, config.getEncoding().name());
        return writer;
    }
}
TOP

Related Classes of com.asakusafw.dmdl.thundergate.emitter.ThunderGateModelEmitter

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.