Package com.asakusafw.testdriver.bulkloader

Source Code of com.asakusafw.testdriver.bulkloader.TableInfo

/**
* 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.testdriver.bulkloader;

import java.text.MessageFormat;
import java.util.Collections;
import java.util.EnumSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;

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

import com.asakusafw.testdriver.core.DataModelDefinition;
import com.asakusafw.testdriver.core.PropertyName;
import com.asakusafw.testdriver.core.PropertyType;
import com.asakusafw.thundergate.runtime.cache.ThunderGateCacheSupport;
import com.asakusafw.vocabulary.bulkloader.OriginalName;

/**
* Target table information.
* @param <T> type of mapped model
*/
public class TableInfo<T> {

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

    private static final Set<PropertyType> SUPPORTED_TYPES;
    static {
        Set<PropertyType> set = EnumSet.allOf(PropertyType.class);
        set.remove(PropertyType.OBJECT);
        set.remove(PropertyType.SEQUENCE);
        SUPPORTED_TYPES = Collections.unmodifiableSet(set);
    }

    private final DataModelDefinition<T> definition;

    private final String tableName;

    private final Map<String, PropertyName> columnsToProperties;

    private final String timestampColumn;

    /**
     * Creates a new instance.
     * If the target model supports the cache feature, this will extract timestamp column.
     * @param definition mapped model definition
     * @param tableName target table name
     * @param columnNames list of column names
     * @throws IllegalArgumentException if some parameters were {@code null}
     * @see #TableInfo(DataModelDefinition, String, List, boolean)
     */
    public TableInfo(
            DataModelDefinition<T> definition,
            String tableName,
            List<String> columnNames) {
        this(definition, tableName, columnNames, true);
    }

    /**
     * Creates a new instance.
     * @param definition mapped model definition
     * @param tableName target table name
     * @param columnNames list of column names
     * @param extractTimestamp {@code true} to extract timestamp column if exists, otherwise {@code false}
     * @throws IllegalArgumentException if some parameters were {@code null}
     * @see #getTimestampColumn()
     */
    public TableInfo(
            DataModelDefinition<T> definition,
            String tableName,
            List<String> columnNames,
            boolean extractTimestamp) {
        if (definition == null) {
            throw new IllegalArgumentException("definition must not be null"); //$NON-NLS-1$
        }
        if (tableName == null) {
            throw new IllegalArgumentException("tableName must not be null"); //$NON-NLS-1$
        }
        if (columnNames == null) {
            throw new IllegalArgumentException("columnNames must not be null"); //$NON-NLS-1$
        }
        this.definition = definition;
        this.tableName = tableName;
        this.columnsToProperties = createMappings(columnNames);
        if (extractTimestamp) {
            this.timestampColumn = extractTimestampColumn();
        } else {
            this.timestampColumn = null;
        }
    }

    /**
     * Returns the model definition mapped the target table.
     * @return the model definition
     */
    public DataModelDefinition<T> getDefinition() {
        return definition;
    }

    /**
     * Returns the target table name.
     * @return the table name
     */
    public String getTableName() {
        return tableName;
    }

    /**
     * Returns the name of last modified timestamp column.
     * @return column name, or {@code null} if not defined
     */
    public String getTimestampColumn() {
        return timestampColumn;
    }

    /**
     * Returns relation between target tables's column names and
     * mapped model's property names.
     * <p>
     * Keys in which returned map keep their order as specified column list in the
     * {@link TableInfo#TableInfo(DataModelDefinition, String, List) constructor}.
     * </p>
     * @return the relation
     */
    public Map<String, PropertyName> getColumnsToProperties() {
        return columnsToProperties;
    }

    private String extractTimestampColumn() {
        assert definition != null;
        if (ThunderGateCacheSupport.class.isAssignableFrom(definition.getModelClass()) == false) {
            return null;
        }
        String columnName;
        try {
            ThunderGateCacheSupport support = definition.getModelClass()
                .asSubclass(ThunderGateCacheSupport.class)
                .newInstance();
            columnName = support.__tgc__TimestampColumn();
        } catch (Exception e) {
            LOG.warn(MessageFormat.format(
                    "テーブル{0}の最終更新時刻のカラム算出に失敗しました",
                    tableName), e);
            return null;
        }
        return columnName;
    }

    private Map<String, PropertyName> createMappings(List<String> columnNames) {
        assert definition != null;
        assert columnNames != null;
        Map<String, PropertyName> allMapping = extractAllMappings();
        Map<String, PropertyName> results = new LinkedHashMap<String, PropertyName>();
        for (String column : columnNames) {
            PropertyName propertyName = allMapping.get(column);
            if (propertyName == null) {
                LOG.warn(MessageFormat.format(
                        "カラム{0}.{1}に対応するプロパティが{2}に見つかりませんでした。このカラムをスキップします",
                        tableName,
                        column,
                        definition.getModelClass().getName()));
                continue;
            }
            results.put(column, propertyName);
        }
        return Collections.unmodifiableMap(results);
    }

    private Map<String, PropertyName> extractAllMappings() {
        assert definition != null;
        Map<String, PropertyName> results = new TreeMap<String, PropertyName>(String.CASE_INSENSITIVE_ORDER);
        for (PropertyName name : definition.getProperties()) {
            PropertyType type = definition.getType(name);
            assert type != null;
            if (acceptsType(name, type) == false) {
                continue;
            }
            String columnName = getOriginalName(name);
            if (columnName == null) {
                // currently may not null
                continue;
            }
            results.put(columnName, name);
        }
        return results;
    }

    private String getOriginalName(PropertyName name) {
        assert name != null;
        assert definition.getType(name) != null;
        OriginalName a = definition.getAnnotation(name, OriginalName.class);
        if (a != null) {
            return a.value();
        }

        Iterator<String> iter = name.getWords().iterator();
        assert iter.hasNext();
        StringBuilder buf = new StringBuilder();
        buf.append(iter.next());
        while (iter.hasNext()) {
            buf.append('_');
            buf.append(iter.next());
        }
        if (LOG.isDebugEnabled()) {
            LOG.debug(MessageFormat.format(
                    "The property \"{1}\" (in {0}) is not annotated with {2}, column name will be inferred as \"{3}\"",
                    definition.getModelClass().getName(),
                    name,
                    OriginalName.class.getSimpleName(),
                    buf));
        }
        return buf.toString();
    }

    private boolean acceptsType(PropertyName name, PropertyType type) {
        assert name != null;
        assert type != null;
        return SUPPORTED_TYPES.contains(type);
    }

    @Override
    public String toString() {
        return MessageFormat.format(
                "Table({0}, model={1}, mapping={2})",
                tableName,
                definition.getModelClass().getName(),
                columnsToProperties);
    }
}
TOP

Related Classes of com.asakusafw.testdriver.bulkloader.TableInfo

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.