Package com.asakusafw.modelgen.emitter

Source Code of com.asakusafw.modelgen.emitter.CommonEmitter

/**
* 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.modelgen.emitter;

import java.math.BigDecimal;
import java.text.MessageFormat;
import java.util.HashSet;
import java.util.Set;

import org.apache.hadoop.io.Text;

import com.asakusafw.modelgen.Constants;
import com.asakusafw.modelgen.model.ModelDescription;
import com.asakusafw.modelgen.model.ModelProperty;
import com.asakusafw.modelgen.model.ModelReference;
import com.asakusafw.modelgen.model.PropertyType;
import com.asakusafw.runtime.value.BooleanOption;
import com.asakusafw.runtime.value.ByteOption;
import com.asakusafw.runtime.value.Date;
import com.asakusafw.runtime.value.DateOption;
import com.asakusafw.runtime.value.DateTime;
import com.asakusafw.runtime.value.DateTimeOption;
import com.asakusafw.runtime.value.DecimalOption;
import com.asakusafw.runtime.value.IntOption;
import com.asakusafw.runtime.value.LongOption;
import com.asakusafw.runtime.value.ShortOption;
import com.asakusafw.runtime.value.StringOption;
import com.asakusafw.utils.java.model.syntax.Expression;
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.Type;
import com.asakusafw.utils.java.model.util.ImportBuilder;
import com.asakusafw.utils.java.model.util.Models;
import com.asakusafw.utils.java.model.util.TypeBuilder;
import com.asakusafw.vocabulary.model.DataModel;
import com.asakusafw.vocabulary.model.JoinedModel;
import com.asakusafw.vocabulary.model.SummarizedModel;

/**
* 名前を構築する。
*/
public class CommonEmitter {

    private final ModelFactory f;

    private final Name baseNamespace;

    /**
     * インスタンスを生成する。
     * @param factory 利用するファクトリ
     * @param baseNamespace 基本となるJavaの名前空間
     */
    public CommonEmitter(
            ModelFactory factory,
            String baseNamespace) {
        this.f = factory;
        this.baseNamespace = Models.toName(f, baseNamespace);
    }

    /**
     * 対象のモデルに対する型を返す。
     * @param reference 対象のモデルへの参照
     * @return 対応する型
     */
    public Type getModelType(ModelReference reference) {
        Name pkg = getPackageNameOf(reference, Constants.CATEGORY_MODEL);
        if (pkg == null) {
            return f.newNamedType(getTypeNameOf(reference));
        } else {
            return f.newNamedType(
                    f.newQualifiedName(
                            pkg,
                            getTypeNameOf(reference)));
        }
    }

    /**
     * 対象のプロパティに対する自然な初期値を返す。
     * @param type プロパティの型
     * @param importer インポートを制御するオブジェクト、不要な場合は{@code null}
     * @return 対応する初期値
     */
    public Expression getInitialValue(
            PropertyType type,
            ImportBuilder importer) {
        switch (type.getKind()) {
        case BOOLEAN:
            return newInstance(importer, BooleanOption.class);
        case BYTE:
            return newInstance(importer, ByteOption.class);
        case SHORT:
            return newInstance(importer, ShortOption.class);
        case INT:
            return newInstance(importer, IntOption.class);
        case LONG:
            return newInstance(importer, LongOption.class);
        case BIG_DECIMAL:
            return newInstance(importer, DecimalOption.class); // TODO precise
        case STRING:
            return newInstance(importer, StringOption.class); // TODO size
        case DATE:
            return newInstance(importer, DateOption.class);
        case DATETIME:
            return newInstance(importer, DateTimeOption.class);

        default:
            throw new IllegalStateException(MessageFormat.format(
                    "Unknown Type: {0}",
                    type));
        }
    }

    private Expression newInstance(
            ImportBuilder importer,
            Class<?> klass,
            Expression... arguments) {
        Type type = Models.toType(f, klass);
        if (importer != null) {
            type = importer.resolve(type);
        }
        return types(type).newObject(arguments).toExpression();
    }

    private TypeBuilder types(Type type) {
        assert type != null;
        return new TypeBuilder(f, type);
    }

    /**
     * 対象のプロパティに対する型を返す。
     * @param type プロパティの型
     * @return 対応する型
     */
    public Type getOptionType(PropertyType type) {
        switch (type.getKind()) {
        case BOOLEAN:
            return Models.toType(f, BooleanOption.class);
        case BYTE:
            return Models.toType(f, ByteOption.class);
        case SHORT:
            return Models.toType(f, ShortOption.class);
        case INT:
            return Models.toType(f, IntOption.class);
        case LONG:
            return Models.toType(f, LongOption.class);
        case BIG_DECIMAL:
            return Models.toType(f, DecimalOption.class);
        case STRING:
            return Models.toType(f, StringOption.class);
        case DATE:
            return Models.toType(f, DateOption.class);
        case DATETIME:
            return Models.toType(f, DateTimeOption.class);

        default:
            throw new IllegalStateException(MessageFormat.format(
                    "Unknown Type: {0}",
                    type));
        }
    }

    /**
     * 対象のプロパティに対する型を返す。
     * @param type プロパティの型
     * @return 対応する型
     */
    public Type getRawType(PropertyType type) {
        switch (type.getKind()) {
        case BOOLEAN:
            return Models.toType(f, boolean.class);
        case BYTE:
            return Models.toType(f, byte.class);
        case SHORT:
            return Models.toType(f, short.class);
        case INT:
            return Models.toType(f, int.class);
        case LONG:
            return Models.toType(f, long.class);
        case BIG_DECIMAL:
            return Models.toType(f, BigDecimal.class);
        case STRING:
            return Models.toType(f, Text.class);
        case DATE:
            return Models.toType(f, Date.class);
        case DATETIME:
            return Models.toType(f, DateTime.class);

        default:
            throw new IllegalStateException(MessageFormat.format(
                    "Unknown Type: {0}",
                    type));
        }
    }

    /**
     * 対象のプロパティに対する型を返す。
     * @param type プロパティの型
     * @return 対応する型
     */
    public Type getAltType(PropertyType type) {
        switch (type.getKind()) {
        case STRING:
            return Models.toType(f, String.class);

        case BOOLEAN:
        case BYTE:
        case SHORT:
        case INT:
        case LONG:
        case BIG_DECIMAL:
        case DATE:
        case DATETIME:
            return null;

        default:
            throw new IllegalStateException(MessageFormat.format(
                    "Unknown Type: {0}",
                    type));
        }
    }

    /**
     * 対象のモデルに対する型の単純名を返す。
     * @param reference 対象のモデル
     * @param categoryName 対象のカテゴリ名
     * @return 対応する名前
     */
    public Name getPackageNameOf(ModelReference reference, String categoryName) {
        // ルートパッケージ: com.example
        // ネームスペース: hoge
        // カテゴリネーム: model
        // -> com.example.hoge.model
        if (reference.isDefaultNameSpace()) {
            return Models.append(f, baseNamespace, categoryName);
        }
        return Models.append(f,
                baseNamespace,
                Models.toName(f, reference.getNamespace()),
                Models.toName(f, categoryName));
    }

    /**
     * 対象のモデルに対する型の単純名を返す。
     * @param reference 対象のモデル
     * @return 対応する名前
     */
    public SimpleName getTypeNameOf(ModelReference reference) {
        JavaName name = JavaName.of(reference.getSimpleName());
        return f.newSimpleName(name.toTypeName());
    }

    /**
     * 対象のプロパティに対するフィールド名を返す。
     * @param propertyName 対象のプロパティ名
     * @param type 対象プロパティの型
     * @return 対応する名前
     */
    public SimpleName getFieldNameOf(String propertyName, PropertyType type) {
        JavaName name = JavaName.of(propertyName);
        return f.newSimpleName(name.toMemberName());
    }

    /**
     * 対象のプロパティに対するゲッター名を返す。
     * @param propertyName 対象のプロパティ名
     * @param type 対象プロパティの型
     * @return 対応する名前
     */
    public SimpleName getGetterNameOf(String propertyName, PropertyType type) {
        JavaName name = JavaName.of(propertyName);
        switch (type.getKind()) {
        case BOOLEAN:
            name.addFirst("is");
            return f.newSimpleName(name.toMemberName());
        default:
            name.addFirst("get");
            return f.newSimpleName(name.toMemberName());
        }
    }

    /**
     * 対象のプロパティに対するセッター名を返す。
     * @param propertyName 対象のプロパティ名
     * @param type 対象プロパティの型
     * @return 対応する名前
     */
    public SimpleName getSetterNameOf(String propertyName, PropertyType type) {
        JavaName name = JavaName.of(propertyName);
        switch (type.getKind()) {
        default:
            name.addFirst("set");
            return f.newSimpleName(name.toMemberName());
        }
    }

    /**
     * 対象のプロパティに対する代替のゲッター名を返す。
     * @param propertyName 対象のプロパティ名
     * @param type 対象プロパティの型
     * @return 対応する名前、存在しない場合は{@code null}
     */
    public SimpleName getAltGetterNameOf(String propertyName, PropertyType type) {
        String original = getGetterNameOf(propertyName, type).getToken();
        return toAltMemberName(original, type);
    }

    /**
     * 対象のプロパティに対する代替のセッター名を返す。
     * @param propertyName 対象のプロパティ名
     * @param type 対象プロパティの型
     * @return 対応する名前、存在しない場合は{@code null}
     */
    public SimpleName getAltSetterNameOf(String propertyName, PropertyType type) {
        String original = getSetterNameOf(propertyName, type).getToken();
        return toAltMemberName(original, type);
    }

    /**
     * 対象の名前に対する代替のメンバー名を返す。
     * @param original 元の名前
     * @param type メンバーの型
     * @return 代替のメンバー名、存在しない場合は{@code null}
     */
    public SimpleName toAltMemberName(String original, PropertyType type) {
        JavaName name = JavaName.of(original);
        switch (type.getKind()) {
        case STRING:
            name.addLast("as");
            name.addLast("string");
            return f.newSimpleName(name.toMemberName());

        case BOOLEAN:
        case BYTE:
        case SHORT:
        case INT:
        case LONG:
        case BIG_DECIMAL:
        case DATE:
        case DATETIME:
            return null;

        default:
            throw new IllegalStateException(MessageFormat.format(
                    "Unknown Type: {0}",
                    type));
        }
    }

    /**
     * 対象のプロパティに対するオプションオブジェクトのゲッター名を返す。
     * @param propertyName 対象のプロパティ名
     * @param type 対象プロパティの型
     * @return 対応する名前
     */
    public SimpleName getOptionGetterNameOf(
            String propertyName,
            PropertyType type) {
        JavaName name = JavaName.of(propertyName);
        name.addFirst("get");
        name.addLast("option");
        return f.newSimpleName(name.toMemberName());
    }

    /**
     * 対象のプロパティに対するオプションオブジェクトのゲッター名を返す。
     * @param propertyName 対象のプロパティ名
     * @param type 対象プロパティの型
     * @return 対応する名前
     */
    public SimpleName getOptionSetterNameOf(
            String propertyName,
            PropertyType type) {
        JavaName name = JavaName.of(propertyName);
        name.addFirst("set");
        name.addLast("option");
        return f.newSimpleName(name.toMemberName());
    }

    /**
     * 他のオブジェクトの内容を取り込むメソッドの名前を返す。
     * @return 対応する名前
     */
    public SimpleName getCopierName() {
        return f.newSimpleName(DataModel.Interface.METHOD_NAME_COPY_FROM);
    }

    /**
     * 結合メソッドの名前を返す。
     * @return 対応する名前
     */
    public SimpleName getJoinerName() {
        return f.newSimpleName(JoinedModel.Interface.METHOD_NAME_JOIN_FROM);
    }

    /**
     * 分割メソッドの名前を返す。
     * @return 対応する名前
     */
    public SimpleName getSplitterName() {
        return f.newSimpleName(JoinedModel.Interface.METHOD_NAME_SPLIT_INTO);
    }

    /**
     * 集計開始メソッドの名前を返す。
     * @return 対応する名前
     */
    public SimpleName getStartSummarizerName() {
        return f.newSimpleName(SummarizedModel.Interface.METHOD_NAME_START_SUMMARIZATION);
    }

    /**
     * 集計追加メソッドの名前を返す。
     * @return 対応する名前
     */
    public SimpleName getCombineSummarizerName() {
        return f.newSimpleName(SummarizedModel.Interface.METHOD_NAME_COMBINE_SUMMARIZATION);
    }

    /**
     * フィールド名と衝突しない変数名を返す。
     * @param model 対象のモデル
     * @param hint 変数名のヒント
     * @return 対応する名前
     */
    public SimpleName getVariableNameOf(ModelDescription model, String hint) {
        Set<String> used = new HashSet<String>();
        for (ModelProperty p : model.getProperties()) {
            used.add(getFieldNameOf(p.getName(), p.getType()).getToken());
        }
        StringBuilder name = new StringBuilder(hint);
        while (used.contains(name.toString())) {
            name.append('_');
        }
        return f.newSimpleName(name.toString());
    }
}
TOP

Related Classes of com.asakusafw.modelgen.emitter.CommonEmitter

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.